Files
backend_fiesta/repositories/userRepository.go
Suriya 36f9cf86e7 Add Super Admin login flag and expose web tenant onboarding
issuperadmin on app_users (schema change already applied to the DB)
is now returned by AppLogin/TenantWebLogin's login response, gated
server-side rather than via a client-supplied roleid. Fixes the login
enrichment query (GetTenantUserById) to LEFT JOIN app_location instead
of INNER JOIN — a tenantless super-admin row was previously silently
dropped, so the login "succeeded" but returned an empty struct.

Also exposes createtenantuser on the web route group (was mob-only).
No repository changes were needed for location auto-provisioning:
GORM was already inserting the nested tenantlocations association on
tenant creation, it just wasn't reachable from the web.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 20:45:27 +05:30

309 lines
10 KiB
Go

package repositories
import (
"fmt"
"strings"
"nearle/models"
"gorm.io/gorm"
)
type UserRepository interface {
GetAllUsers(roleID, tenantID, pageno, pagesize int, keyword string) ([]models.UserInfo, error)
GetUserByID(uid int) (models.UserInfo, error)
Login(user models.User) (models.UserInfo, error)
FindUserID(authname, contactno string, configid int) (int, error)
GetTenantUserByID(userid int) (models.TenantUserInfo, error)
UpdateStaff(user models.User) error
GetUserByAuthname(authname string, configid int) (int, string, string)
GetUserByContactNo(contactno string, configid int) (int, string, string)
UpdateFCMToken(userid int, token string) error
GetTenantUserById(userid int) models.TenantUserInfo
CreateUser(user models.User) (int, error)
GetUserById(uid int) (models.UserInfo, error)
GetUserLogin(field, value string, configid int) (int, string, string, int)
UpdateUserFcmToken(uid int, token string) error
GetLocationStatus(locationid int) string
DeleteUser(userid int) error
}
type userRepository struct {
db *gorm.DB
}
func NewUserRepository(db *gorm.DB) UserRepository {
return &userRepository{db: db}
}
func (r *userRepository) GetAllUsers(roleID, tenantID, pageno, pagesize int, keyword string) ([]models.UserInfo, error) {
var users []models.UserInfo
var params []interface{}
var queryBuilder strings.Builder
offset := (pageno - 1) * pagesize
queryBuilder.WriteString(`SELECT
a.userid, a.authname, a.email, a.configid, a.roleid, a.authmode, a.contactno,
a.firstname, a.lastname, CONCAT(a.firstname, ' ', a.lastname) AS fullname,
a.address, a.suburb, a.city, a.state, a.postcode,
a.userfcmtoken, a.pin, a.deviceid, a.devicetype, a.tenantid, a.status, a.shiftid,
a.applocationid, b.locationname AS applocation, b.latitude AS applatitude, concat(c.starttime, ' - ', c.endtime) as shiftname,
b.longitude AS applongitude, b.radius AS appradius
FROM app_users a
LEFT JOIN app_location b ON a.applocationid = b.applocationid
LEFT JOIN ridershifts c ON a.shiftid = c.shiftid
WHERE 1=1`)
if roleID != 0 {
queryBuilder.WriteString(" AND a.roleid = ?")
params = append(params, roleID)
}
if tenantID != 0 {
queryBuilder.WriteString(" AND a.tenantid = ?")
params = append(params, tenantID)
}
if keyword != "" {
queryBuilder.WriteString(` AND (
LOWER(a.firstname) LIKE ? OR
LOWER(a.contactno) LIKE ? OR
LOWER(a.suburb) LIKE ?
)`)
search := "%" + strings.ToLower(keyword) + "%"
params = append(params, search, search, search)
}
queryBuilder.WriteString(" ORDER BY a.userid DESC LIMIT ? OFFSET ?")
params = append(params, pagesize, offset)
print(queryBuilder.String())
if err := r.db.Raw(queryBuilder.String(), params...).Scan(&users).Error; err != nil {
return nil, err
}
for i := range users {
users[i].Status = strings.ToLower(users[i].Status)
}
return users, nil
}
func (r *userRepository) GetUserByID(uid int) (models.UserInfo, error) {
var user models.UserInfo
q := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,a.password,a.address,a.suburb,a.city,a.state,a.postcode,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.shiftid,a.locationid,
a.applocationid,b.locationname as applocation,b.latitude as applatitude,b.longitude as applongitude, b.radius as appradius,
concat(c.starttime, ' - ', c.endtime) as shiftname, a.status
FROM app_users a
INNER JOIN app_location b ON a.applocationid = b.applocationid
LEFT JOIN ridershifts c ON a.shiftid = c.shiftid
WHERE a.userid = ?`
if err := r.db.Raw(q, uid).Scan(&user).Error; err != nil {
return models.UserInfo{}, err
}
user.Status = strings.ToLower(user.Status)
return user, nil
}
func (r *userRepository) Login(user models.User) (models.UserInfo, error) {
var uid int
var userInfo models.UserInfo
var q string
if user.Authname != "" {
q = `SELECT a.userid FROM app_users a
WHERE a.authname = ? AND a.configid = ?`
if err := r.db.Raw(q, user.Authname, user.Configid).Scan(&uid).Error; err != nil {
return models.UserInfo{}, err
}
} else {
q = `SELECT a.userid FROM app_users a
WHERE a.contactno = ? AND a.configid = ?`
if err := r.db.Raw(q, user.Contactno, user.Configid).Scan(&uid).Error; err != nil {
return models.UserInfo{}, err
}
}
if uid == 0 {
return models.UserInfo{}, gorm.ErrRecordNotFound
}
// ✅ Update FCM token in app_users table if provided
if user.Userfcmtoken != "" {
if err := r.db.Table("app_users").
Where("userid = ?", uid).
Update("userfcmtoken", user.Userfcmtoken).Error; err != nil {
return models.UserInfo{}, err
}
}
userInfo, err := r.GetUserByID(uid)
if err != nil {
return models.UserInfo{}, err
}
return userInfo, nil
}
func (r *userRepository) FindUserID(authname, contactno string, configid int) (int, error) {
var uid int
var query string
if authname != "" {
query = `SELECT a.userid FROM app_users a WHERE a.authname = ? AND a.configid = ?`
if err := r.db.Raw(query, authname, configid).Scan(&uid).Error; err != nil {
return 0, err
}
} else {
query = `SELECT a.userid FROM app_users a WHERE a.contactno = ? AND a.configid = ?`
if err := r.db.Raw(query, contactno, configid).Scan(&uid).Error; err != nil {
return 0, err
}
}
return uid, nil
}
func (r *userRepository) GetTenantUserByID(userid int) (models.TenantUserInfo, error) {
var info models.TenantUserInfo
query := `SELECT a.userid, a.authname, a.contactno, a.tenantid, t.tenantname
FROM app_users a
LEFT JOIN tenants t ON a.tenantid = t.tenantid
WHERE a.userid = ?`
if err := r.db.Raw(query, userid).Scan(&info).Error; err != nil {
return info, err
}
return info, nil
}
func (r *userRepository) UpdateStaff(user models.User) error {
return r.db.Table("app_users").Where("userid = ?", user.Userid).Updates(&user).Error
}
func (r *userRepository) GetUserByAuthname(authname string, configid int) (int, string, string) {
var uid int
var password, status string
query := `SELECT userid, password, status FROM app_users WHERE authname = ? AND configid = ?`
r.db.Raw(query, authname, configid).Row().Scan(&uid, &password, &status)
return uid, password, status
}
func (r *userRepository) GetUserByContactNo(contactno string, configid int) (int, string, string) {
var uid int
var password, status string
query := `SELECT userid, password, status FROM app_users WHERE contactno = ? AND configid = ?`
r.db.Raw(query, contactno, configid).Row().Scan(&uid, &password, &status)
return uid, password, status
}
func (r *userRepository) UpdateFCMToken(userid int, token string) error {
query := `UPDATE app_users SET userfcmtoken = ? WHERE userid = ?`
return r.db.Exec(query, token, userid).Error
}
func (r *userRepository) GetTenantUserById(userid int) models.TenantUserInfo {
var info models.TenantUserInfo
// app_location is LEFT JOINed (not INNER) so a user with no matching
// tenant/applocation row — e.g. a super admin, tenantid=0 — still comes
// back with their own fields (issuperadmin included) instead of the
// whole query silently returning zero rows.
query := `
SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.locationid,a.applocationid,
a.issuperadmin,
b.partnerid,b.moduleid,b.categoryid as categoryid,b.subcategoryid as subcategoryid,
b.applocationid,b.tenantname,b.address as tenantaddress,b.state as tenantstate,b.city as tenantcity,
b.postcode as tenantpostcode,b.latitude as tenantlat,b.longitude as tenantlong,c.locationname AS applocation,
c.latitude as applatitude,c.longitude as applongitude,c.radius as appradius, d.categoryname, e.locationname
from app_users a
LEFT JOIN tenants b ON a.tenantid=b.tenantid
LEFT JOIN app_location c on c.applocationid=b.applocationid
LEFT JOIN app_category d ON b.categoryid=d.categoryid
LEFT JOIN tenantlocations e ON a.locationid=e.locationid
WHERE a.userid = ?
`
r.db.Raw(query, userid).Scan(&info)
print(query)
return info
}
func (r *userRepository) CreateUser(user models.User) (int, error) {
tx := r.db.Begin()
if err := tx.Table("app_users").Create(&user).Error; err != nil {
tx.Rollback()
return 0, err
}
if err := tx.Commit().Error; err != nil {
return 0, err
}
return user.Userid, nil
}
func (r *userRepository) GetUserById(uid int) (models.UserInfo, error) {
var user models.UserInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,a.password,a.address,a.suburb,a.city,a.state,a.postcode,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.shiftid,
a.applocationid,b.locationname as applocation,b.latitude as applatitude,b.longitude as applongitude, b.radius as appradius , concat(c.starttime, ' - ', c.endtime) as shiftname, a.status
FROM app_users a
INNER JOIN app_location b on a.applocationid=b.applocationid
LEFT JOIN ridershifts c ON a.shiftid = c.shiftid
WHERE a.userid= ?`
if err := r.db.Raw(q1, uid).Scan(&user).Error; err != nil {
return models.UserInfo{}, err
}
user.Status = strings.ToLower(user.Status)
return user, nil
}
func (r *userRepository) GetUserLogin(field, value string, configid int) (int, string, string, int) {
var uid, roleid int
var password, status string
query := fmt.Sprintf(`
SELECT userid, password, status, roleid
FROM app_users
WHERE %s = ? AND configid = ?`, field)
r.db.Raw(query, value, configid).Row().Scan(&uid, &password, &status, &roleid)
return uid, password, status, roleid
}
func (r *userRepository) UpdateUserFcmToken(userid int, fcmToken string) error {
query := `UPDATE app_users SET userfcmtoken = ? WHERE userid = ?`
return r.db.Exec(query, fcmToken, userid).Error
}
func (r *userRepository) GetLocationStatus(locationid int) string {
var status string
query := `SELECT status FROM tenantlocations WHERE locationid = ?`
r.db.Raw(query, locationid).Row().Scan(&status)
return status
}
func (r *userRepository) DeleteUser(userid int) error {
return r.db.Table("app_users").Where("userid = ?", userid).Delete(&models.User{}).Error
}