package common import ( "database/sql" "devel.mephi.ru/dyokunev/cps-api/app/common/db" models "devel.mephi.ru/dyokunev/cps-models" acdir "devel.mephi.ru/dyokunev/go-acdir" asuModels "devel.mephi.ru/dyokunev/go-asu-models" helpers "devel.mephi.ru/dyokunev/go-helpers" mysqlDriver "github.com/go-sql-driver/mysql" "github.com/revel/revel" "strconv" "strings" "sync" "time" ) type Permissions struct { IsFixOk bool IsFullAccess bool IsVoip bool HeadedUnits asuModels.Units AllowedUnits asuModels.Units AllowedPeople asuModels.People } var ( userInfoMap = map[string]UserInfo{} userInfoMapMutex = &sync.Mutex{} getUserInfoMutex = &sync.Mutex{} ) func InitUserInfo() { go func() { for { userInfoMapMutex.Lock() userInfoMap = map[string]UserInfo{} userInfoMapMutex.Unlock() time.Sleep(time.Minute * 5) } }() } func DownloadUserInfo(username string) UserInfo { var info UserInfo info.Username = strings.ToLower(username) ldapEntry, err := acdir.GetEntryByUsername(username) if err == nil { if ldapEntry.EmpGUID == 0 { //panic("ldapEntry.EmpGUID == 0") return info } info.EmpGUID = ldapEntry.EmpGUID info.Permissions.HeadedUnits = asuModels.GetUnitsHeadedBy(info.EmpGUID) info.Permissions.HeadedUnits.DoRecursive(func(unit *asuModels.Unit, argI interface{}) bool { info.Permissions.AllowedUnits = append(info.Permissions.AllowedUnits, *unit) return true }, nil) info.Permissions.AllowedPeople = info.Permissions.AllowedUnits.PrepareFormulars(true, false).GetFormulars().PreparePeople().GetPeople() me, err := asuModels.PersonSQL.First(asuModels.Person{EmpGUID: info.EmpGUID}) if err != nil { panic(err) } info.Permissions.AllowedPeople = append(info.Permissions.AllowedPeople, me) } else { if err != acdir.ErrNoRows { panic(err) } } cpsUser, err := models.CpsUserSQL.First(models.CpsUser{Username: username}) for err == mysqlDriver.ErrInvalidConn { // TODO: remove this hacky workaround. ATM, it solved floating bug: "invalid connection" cpsUser, err = models.CpsUserSQL.First(models.CpsUser{Username: username}) } if err != nil && err != sql.ErrNoRows { panic(err) } if err == nil { info.Permissions = AppendPermissions(cpsUser, info.Permissions) } // Checking if the user has full access. In this case it's recommended to disable filters in app/controllers/controller.go:Controller.init() { rows, err := db.Sdapi1Raw.Query("SELECT COUNT(*) FROM unit") if err != nil { panic(err) } defer rows.Close() if !rows.Next() { panic("This shouldn't happend") } var unitsCount int err = rows.Scan(&unitsCount) if err != nil { panic(err) } if len(info.Permissions.AllowedUnits) > unitsCount { panic("This shouldn't happend") } if len(info.Permissions.AllowedUnits) == unitsCount { info.Permissions.IsFullAccess = true } } return info } func GetUserInfo(username string) UserInfo { getUserInfoMutex.Lock() defer func() { getUserInfoMutex.Unlock() }() username = strings.ToLower(username) userInfoMapMutex.Lock() info := userInfoMap[username] userInfoMapMutex.Unlock() if info.Username != username { info = DownloadUserInfo(username) userInfoMapMutex.Lock() userInfoMap[username] = info userInfoMapMutex.Unlock() } return info } func AppendPermissions(cpsUser models.CpsUser, permissions Permissions) Permissions { alreadySetUnitIds := map[int]bool{} for _, unit := range permissions.AllowedUnits { alreadySetUnitIds[unit.Id] = true } if cpsUser.UnitCodePatternsStr != nil { *cpsUser.UnitCodePatternsStr = strings.Replace(helpers.RemoveAllStringByPattern(*cpsUser.UnitCodePatternsStr, "[^0-9%*]+"), "*", "%", -1) if len(*cpsUser.UnitCodePatternsStr) > 0 { unitCodePatterns := strings.Split(*cpsUser.UnitCodePatternsStr, ",") for _, pattern := range unitCodePatterns { if pattern == "%" { var err error permissions.AllowedUnits, err = asuModels.UnitSQL.Select() if err != nil { panic(err) } permissions.AllowedPeople, err = asuModels.PersonSQL.Select() if err != nil { panic(err) } continue } pattern = "1" + pattern var units asuModels.Units units, err := asuModels.UnitSQL.ActiveOnly().Select("Code LIKE ?", pattern) if err != nil { panic(err) } units.PrepareChildrenTree().DoRecursive(func(unit *asuModels.Unit, argI interface{}) bool { if alreadySetUnitIds[unit.Id] { return true } permissions.AllowedUnits = append(permissions.AllowedUnits, *unit) permissions.AllowedPeople = append(permissions.AllowedPeople, unit.PrepareFormulars().GetFormulars().PreparePeople().GetPeople()...) return true }, nil) } } } for _, unit := range permissions.AllowedUnits { alreadySetUnitIds[unit.Id] = true } if cpsUser.EmpGUIDsStr != nil { *cpsUser.EmpGUIDsStr = helpers.RemoveAllStringByPattern(*cpsUser.EmpGUIDsStr, "[^0-9]+") if len(*cpsUser.EmpGUIDsStr) > 0 { EmpGUIDsS := strings.Split(*cpsUser.EmpGUIDsStr, ",") for _, empGUIDS := range EmpGUIDsS { empGUID, err := strconv.Atoi(empGUIDS) if err != nil { panic(err) } person, err := asuModels.PersonSQL.First(asuModels.Person{EmpGUID: empGUID}) if err == sql.ErrNoRows { revel.WARN.Printf("Cannot find person with EmpGUID == %v", empGUID) continue } if err != nil { panic(nil) } permissions.AllowedPeople = append(permissions.AllowedPeople, person) } } } permissions.AllowedPeople = permissions.AllowedPeople.Deduplicate() return permissions } func (p Permissions) GetShortForm() map[string]interface{} { permissions := map[string]interface{}{} permissions["isFullAccess"] = p.IsFullAccess permissions["isFixOk"] = p.IsFixOk if !p.IsFullAccess { var allowedUnits []map[string]interface{} for _, allowedUnit := range p.AllowedUnits { allowedUnits = append(allowedUnits, map[string]interface{}{ "id": allowedUnit.Id, "code": allowedUnit.Code, "persNumber": allowedUnit.PersNumber, }) } permissions["allowedUnits"] = allowedUnits permissions["allowedPeople"] = p.AllowedPeople.GetEmpGUIDs() } return permissions }