add groups to claims and assign user as no admin
This commit is contained in:
parent
c2104a3374
commit
1b935868b6
3 changed files with 150 additions and 90 deletions
|
@ -283,34 +283,6 @@ func (err *ErrListCannotBelongToAPseudoNamespace) HTTPError() web.HTTPError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrListMustBelongToANamespace represents an error where a list must belong to a namespace
|
|
||||||
type ErrListMustBelongToANamespace struct {
|
|
||||||
ListID int64
|
|
||||||
NamespaceID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrListMustBelongToANamespace checks if an error is a list must belong to a namespace error.
|
|
||||||
func IsErrListMustBelongToANamespace(err error) bool {
|
|
||||||
_, ok := err.(*ErrListMustBelongToANamespace)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err *ErrListMustBelongToANamespace) Error() string {
|
|
||||||
return fmt.Sprintf("List must belong to a namespace [ListID: %d, NamespaceID: %d]", err.ListID, err.NamespaceID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeListMustBelongToANamespace holds the unique world-error code of this error
|
|
||||||
const ErrCodeListMustBelongToANamespace = 3010
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err *ErrListMustBelongToANamespace) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{
|
|
||||||
HTTPCode: http.StatusPreconditionFailed,
|
|
||||||
Code: ErrCodeListMustBelongToANamespace,
|
|
||||||
Message: "This list must belong to a namespace.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================
|
// ================
|
||||||
// List task errors
|
// List task errors
|
||||||
// ================
|
// ================
|
||||||
|
@ -819,62 +791,6 @@ func (err ErrInvalidTaskFilterValue) HTTPError() web.HTTPError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrAttachmentDoesNotBelongToTask represents an error where the provided task cover attachment does not belong to the same task
|
|
||||||
type ErrAttachmentDoesNotBelongToTask struct {
|
|
||||||
TaskID int64
|
|
||||||
AttachmentID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrAttachmentAndCoverMustBelongToTheSameTask checks if an error is ErrAttachmentDoesNotBelongToTask.
|
|
||||||
func IsErrAttachmentAndCoverMustBelongToTheSameTask(err error) bool {
|
|
||||||
_, ok := err.(ErrAttachmentDoesNotBelongToTask)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrAttachmentDoesNotBelongToTask) Error() string {
|
|
||||||
return fmt.Sprintf("Task attachment and cover image do not belong to the same task [TaskID: %d, AttachmentID: %d]", err.TaskID, err.AttachmentID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeAttachmentDoesNotBelongToTask holds the unique world-error code of this error
|
|
||||||
const ErrCodeAttachmentDoesNotBelongToTask = 4020
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrAttachmentDoesNotBelongToTask) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{
|
|
||||||
HTTPCode: http.StatusBadRequest,
|
|
||||||
Code: ErrCodeAttachmentDoesNotBelongToTask,
|
|
||||||
Message: "This attachment does not belong to that task.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUserAlreadyAssigned represents an error where the user is already assigned to this task
|
|
||||||
type ErrUserAlreadyAssigned struct {
|
|
||||||
TaskID int64
|
|
||||||
UserID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrUserAlreadyAssigned checks if an error is ErrUserAlreadyAssigned.
|
|
||||||
func IsErrUserAlreadyAssigned(err error) bool {
|
|
||||||
_, ok := err.(ErrUserAlreadyAssigned)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrUserAlreadyAssigned) Error() string {
|
|
||||||
return fmt.Sprintf("User is already assigned to task [TaskID: %d, UserID: %d]", err.TaskID, err.UserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeUserAlreadyAssigned holds the unique world-error code of this error
|
|
||||||
const ErrCodeUserAlreadyAssigned = 4021
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrUserAlreadyAssigned) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{
|
|
||||||
HTTPCode: http.StatusBadRequest,
|
|
||||||
Code: ErrCodeUserAlreadyAssigned,
|
|
||||||
Message: "This user is already assigned to that task.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =================
|
// =================
|
||||||
// Namespace errors
|
// Namespace errors
|
||||||
// =================
|
// =================
|
||||||
|
@ -1095,6 +1011,28 @@ func (err ErrTeamDoesNotExist) HTTPError() web.HTTPError {
|
||||||
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeTeamDoesNotExist, Message: "This team does not exist."}
|
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeTeamDoesNotExist, Message: "This team does not exist."}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ErrTeamsDoNotExist struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrTeamDoNotExist checks if an error is ErrTeamDoesNotExist.
|
||||||
|
func IsErrTeamsDoNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrTeamsDoNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrTeamsDoNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("Team does not exist [Team ID: %d]", err.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeTeamDoesNotExist holds the unique world-error code of this error
|
||||||
|
const ErrCodeTeamsDoNotExist = 6002
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrTeamsDoNotExist) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeTeamDoesNotExist, Message: "No team with given name exists."}
|
||||||
|
}
|
||||||
|
|
||||||
// ErrTeamAlreadyHasAccess represents an error where a team already has access to a list/namespace
|
// ErrTeamAlreadyHasAccess represents an error where a team already has access to a list/namespace
|
||||||
type ErrTeamAlreadyHasAccess struct {
|
type ErrTeamAlreadyHasAccess struct {
|
||||||
TeamID int64
|
TeamID int64
|
||||||
|
|
|
@ -79,7 +79,7 @@ type TeamMember struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName makes beautiful table names
|
// TableName makes beautiful table names
|
||||||
func (*TeamMember) TableName() string {
|
func (TeamMember) TableName() string {
|
||||||
return "team_members"
|
return "team_members"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +119,34 @@ func GetTeamByID(s *xorm.Session, id int64) (team *Team, err error) {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func GetTeamsByName(s *xorm.Session, name string) (teams []*Team, err error) {
|
||||||
|
if name == "" {
|
||||||
|
return teams, ErrTeamsDoNotExist{name}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ts []*Team
|
||||||
|
|
||||||
|
exists := s.
|
||||||
|
Where("name = ?", name).
|
||||||
|
Find(&ts)
|
||||||
|
if exists != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(ts) == 0 {
|
||||||
|
return ts, ErrTeamsDoNotExist{name}
|
||||||
|
}
|
||||||
|
|
||||||
|
// //for each ts
|
||||||
|
// teamSlice := []*Team{ts}
|
||||||
|
// err = addMoreInfoToTeams(s, teamSlice)
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
teams = ts
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func addMoreInfoToTeams(s *xorm.Session, teams []*Team) (err error) {
|
func addMoreInfoToTeams(s *xorm.Session, teams []*Team) (err error) {
|
||||||
|
|
||||||
|
@ -282,6 +310,37 @@ func (t *Team) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Team) CreateNoAdmin(s *xorm.Session, a web.Auth) (err error) {
|
||||||
|
doer, err := user.GetFromAuth(a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have a name
|
||||||
|
if t.Name == "" {
|
||||||
|
return ErrTeamNameCannotBeEmpty{}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.CreatedByID = doer.ID
|
||||||
|
t.CreatedBy = doer
|
||||||
|
|
||||||
|
_, err = s.Insert(t)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the current user as member and admin
|
||||||
|
tm := TeamMember{TeamID: t.ID, Username: doer.Username, Admin: false}
|
||||||
|
if err = tm.Create(s, doer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return events.Dispatch(&TeamCreatedEvent{
|
||||||
|
Team: t,
|
||||||
|
Doer: a,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Delete deletes a team
|
// Delete deletes a team
|
||||||
// @Summary Deletes a team
|
// @Summary Deletes a team
|
||||||
// @Description Delets a team. This will also remove the access for all users in that team.
|
// @Description Delets a team. This will also remove the access for all users in that team.
|
||||||
|
|
|
@ -52,6 +52,7 @@ type Provider struct {
|
||||||
OriginalAuthURL string `json:"-"`
|
OriginalAuthURL string `json:"-"`
|
||||||
AuthURL string `json:"auth_url"`
|
AuthURL string `json:"auth_url"`
|
||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
ClientSecret string `json:"-"`
|
ClientSecret string `json:"-"`
|
||||||
openIDProvider *oidc.Provider
|
openIDProvider *oidc.Provider
|
||||||
Oauth2Config *oauth2.Config `json:"-"`
|
Oauth2Config *oauth2.Config `json:"-"`
|
||||||
|
@ -62,6 +63,7 @@ type claims struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
PreferredUsername string `json:"preferred_username"`
|
PreferredUsername string `json:"preferred_username"`
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
|
Group []string `json:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -188,22 +190,83 @@ func HandleCallback(c echo.Context) error {
|
||||||
|
|
||||||
// Check if we have seen this user before
|
// Check if we have seen this user before
|
||||||
u, err := getOrCreateUser(s, cl, idToken.Issuer, idToken.Subject)
|
u, err := getOrCreateUser(s, cl, idToken.Issuer, idToken.Subject)
|
||||||
|
|
||||||
|
log.Errorf("Issuer %s: %v", idToken.Issuer, err)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = s.Rollback()
|
_ = s.Rollback()
|
||||||
log.Errorf("Error creating new user for provider %s: %v", provider.Name, err)
|
log.Errorf("Error creating new user for provider %s: %v", provider.Name, err)
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we have seen this user before
|
||||||
|
teams := GetOrCreateTeamsByNames(s, cl.Group, u)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error verifying team for name %v, got %v", cl.Name, teams, err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
for _, team := range teams {
|
||||||
|
tm := models.TeamMember{TeamID: team.ID, Username: u.Username}
|
||||||
|
if err = tm.Create(s, u); err != nil {
|
||||||
|
switch t := err.(type) {
|
||||||
|
case *models.ErrUserIsMemberOfTeam:
|
||||||
|
log.Errorf("ErrUserIsMemberOfTeam", t)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
log.Errorf("Error assigning User to team", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = s.Commit()
|
err = s.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create token
|
// Create token
|
||||||
return auth.NewUserAuthTokenResponse(u, c, false)
|
return auth.NewUserAuthTokenResponse(u, c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetOrCreateTeamsByNames(s *xorm.Session, teamNames []string, u *user.User) (te []models.Team) {
|
||||||
|
// Check if a team with given name exists should be after user creation
|
||||||
|
|
||||||
|
//TODO: 1. Create team if not exist
|
||||||
|
te = []models.Team{}
|
||||||
|
for _, t := range teamNames {
|
||||||
|
team, err := models.GetTeamsByName(s, t)
|
||||||
|
|
||||||
|
if models.IsErrTeamsDoNotExist(err) {
|
||||||
|
log.Errorf("No such Team: %v, got %v", t, team, err)
|
||||||
|
tea := &models.Team{
|
||||||
|
Name: t,
|
||||||
|
}
|
||||||
|
// TODO: here the user who creates the Team is automatically admin. That shoud not be the case..?
|
||||||
|
err := tea.CreateNoAdmin(s, u)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Teams: %v, err: %v", tea, err)
|
||||||
|
} else {
|
||||||
|
te = append(te, *tea)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if multiple teams with same name are found,
|
||||||
|
if len(team) == 1 {
|
||||||
|
te = append(te, *team[len(team)-1])
|
||||||
|
} else {
|
||||||
|
log.Errorf("Multiple Teams have the same name: %v, ", team[len(team)-1].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return te
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign user to team
|
||||||
|
// remove user from team if not in group
|
||||||
|
// if multiple teams found with same name -> do nothing
|
||||||
|
// optional: assign by id
|
||||||
|
//
|
||||||
|
|
||||||
func getOrCreateUser(s *xorm.Session, cl *claims, issuer, subject string) (u *user.User, err error) {
|
func getOrCreateUser(s *xorm.Session, cl *claims, issuer, subject string) (u *user.User, err error) {
|
||||||
|
|
||||||
// Check if the user exists for that issuer and subject
|
// Check if the user exists for that issuer and subject
|
||||||
u, err = user.GetUserWithEmail(s, &user.User{
|
u, err = user.GetUserWithEmail(s, &user.User{
|
||||||
Issuer: issuer,
|
Issuer: issuer,
|
||||||
|
|
Loading…
Reference in a new issue