diff --git a/pkg/cmd/user.go b/pkg/cmd/user.go index e62b4b4f4..261d0105e 100644 --- a/pkg/cmd/user.go +++ b/pkg/cmd/user.go @@ -191,7 +191,7 @@ var userCreateCmd = &cobra.Command{ err = models.CreateNewProjectForUser(s, newUser) if err != nil { _ = s.Rollback() - log.Fatalf("Error creating new namespace for user: %s", err) + log.Fatalf("Error creating new project for user: %s", err) } if err := s.Commit(); err != nil { diff --git a/pkg/integrations/archived_test.go b/pkg/integrations/archived_test.go index 50ab31e5d..9ecb82ba3 100644 --- a/pkg/integrations/archived_test.go +++ b/pkg/integrations/archived_test.go @@ -17,7 +17,6 @@ package integrations import ( - "net/url" "testing" "code.vikunja.io/api/pkg/models" @@ -26,32 +25,27 @@ import ( ) // This tests the following behaviour: -// 1. A namespace should not be editable if it is archived. -// 1. With the exception being to un-archive it. -// 2. A project which belongs to an archived namespace cannot be edited. +// 2. A project which belongs to an archived project cannot be edited. // 3. An archived project should not be editable. // 1. Except for un-archiving it. -// 4. It is not possible to un-archive a project individually if its namespace is archived. -// 5. Creating new projects on an archived namespace should not work. +// 4. It is not possible to un-archive a project individually if its parent project is archived. +// 5. Creating new child projects in an archived project should not work. // 6. Creating new tasks on an archived project should not work. -// 7. Creating new tasks on a project who's namespace is archived should not work. +// 7. Creating new tasks on a project whose parent project is archived should not work. // 8. Editing tasks on an archived project should not work. -// 9. Editing tasks on a project who's namespace is archived should not work. -// 10. Archived namespaces should not appear in the project with all namespaces. -// 11. Archived projects should not appear in the project with all projects. -// 12. Projects who's namespace is archived should not appear in the project with all projects. +// 9. Editing tasks on a project whose parent project is archived should not work. +// 11. Archived projects should not appear in the list with all projects. +// 12. Projects whose parent project is archived should not appear in the project with all projects. // // All of this is tested through integration tests because it's not yet clear if this will be implemented directly // or with some kind of middleware. // -// Maybe the inheritance of projects from namespaces could be solved with some kind of is_archived_inherited flag - +// Maybe the inheritance of projects from parents could be solved with some kind of is_archived_inherited flag - // that way I'd only need to implement the checking on a project level and update the flag for all projects once the -// namespace is archived. The archived flag would then be used to not accedentially unarchive projects which were -// already individually archived when the namespace was archived. -// Should still test it all though. +// project is archived. The archived flag would then be used to not accedentially unarchive projects which were +// already individually archived when the parent project was archived. // -// Namespace 16 is archived -// Project 21 belongs to namespace 16 +// Project 21 belongs to project 16 // Project 22 is archived individually func TestArchived(t *testing.T) { @@ -62,13 +56,6 @@ func TestArchived(t *testing.T) { }, t: t, } - testNamespaceHandler := webHandlerTest{ - user: &testuser1, - strFunc: func() handler.CObject { - return &models.Namespace{} - }, - t: t, - } testTaskHandler := webHandlerTest{ user: &testuser1, strFunc: func() handler.CObject { @@ -105,34 +92,6 @@ func TestArchived(t *testing.T) { t: t, } - t.Run("namespace", func(t *testing.T) { - t.Run("not editable", func(t *testing.T) { - _, err := testNamespaceHandler.testUpdateWithUser(nil, map[string]string{"namespace": "16"}, `{"title":"TestIpsum","is_archived":true}`) - assert.Error(t, err) - assertHandlerErrorCode(t, err, models.ErrCodeNamespaceIsArchived) - }) - t.Run("unarchivable", func(t *testing.T) { - rec, err := testNamespaceHandler.testUpdateWithUser(nil, map[string]string{"namespace": "16"}, `{"title":"TestIpsum","is_archived":false}`) - assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `"is_archived":false`) - }) - t.Run("no new projects", func(t *testing.T) { - _, err := testProjectHandler.testCreateWithUser(nil, map[string]string{"namespace": "16"}, `{"title":"Lorem"}`) - assert.Error(t, err) - assertHandlerErrorCode(t, err, models.ErrCodeNamespaceIsArchived) - }) - t.Run("should not appear in the project", func(t *testing.T) { - rec, err := testNamespaceHandler.testReadAllWithUser(nil, nil) - assert.NoError(t, err) - assert.NotContains(t, rec.Body.String(), `"title":"Archived testnamespace16"`) - }) - t.Run("should appear in the project if explicitly requested", func(t *testing.T) { - rec, err := testNamespaceHandler.testReadAllWithUser(url.Values{"is_archived": []string{"true"}}, nil) - assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `"title":"Archived testnamespace16"`) - }) - }) - t.Run("project", func(t *testing.T) { taskTests := func(taskID string, errCode int, t *testing.T) { @@ -194,8 +153,8 @@ func TestArchived(t *testing.T) { }) } - // The project belongs to an archived namespace - t.Run("archived namespace", func(t *testing.T) { + // The project belongs to an archived parent project + t.Run("archived parent project", func(t *testing.T) { t.Run("not editable", func(t *testing.T) { _, err := testProjectHandler.testUpdateWithUser(nil, map[string]string{"project": "21"}, `{"title":"TestIpsum","is_archived":true}`) assert.Error(t, err) diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 76dfe3201..cfb363e35 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -34,9 +34,6 @@ const ( // UserCountKey is the name of the key we use to store total users in redis UserCountKey = `usercount` - // NamespaceCountKey is the name of the key we use to store the amount of total namespaces in redis - NamespaceCountKey = `namespacecount` - // TaskCountKey is the name of the key we use to store the amount of total tasks in redis TaskCountKey = `taskcount` @@ -89,18 +86,6 @@ func InitMetrics() { log.Criticalf("Could not register metrics for %s: %s", UserCountKey, err) } - // Register total Namespaces count metric - err = registry.Register(promauto.NewGaugeFunc(prometheus.GaugeOpts{ - Name: "vikunja_namespace_count", - Help: "The total number of namespaces on this instance", - }, func() float64 { - count, _ := GetCount(NamespaceCountKey) - return float64(count) - })) - if err != nil { - log.Criticalf("Could not register metrics for %s: %s", NamespaceCountKey, err) - } - // Register total Tasks count metric err = registry.Register(promauto.NewGaugeFunc(prometheus.GaugeOpts{ Name: "vikunja_task_count", diff --git a/pkg/models/error.go b/pkg/models/error.go index 12716b590..a1470ad2c 100644 --- a/pkg/models/error.go +++ b/pkg/models/error.go @@ -255,65 +255,37 @@ func (err ErrProjectIsArchived) HTTPError() web.HTTPError { return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeProjectIsArchived, Message: "This project is archived. Editing or creating new tasks is not possible."} } -// ErrProjectCannotBelongToAPseudoNamespace represents an error where a project cannot belong to a pseudo namespace -type ErrProjectCannotBelongToAPseudoNamespace struct { - ProjectID int64 - NamespaceID int64 +// ErrProjectCannotBelongToAPseudoParentProject represents an error where a project cannot belong to a pseudo project +type ErrProjectCannotBelongToAPseudoParentProject struct { + ProjectID int64 + ParentProjectID int64 } -// IsErrProjectCannotBelongToAPseudoNamespace checks if an error is a project is archived error. -func IsErrProjectCannotBelongToAPseudoNamespace(err error) bool { - _, ok := err.(*ErrProjectCannotBelongToAPseudoNamespace) +// IsErrProjectCannotBelongToAPseudoParentProject checks if an error is a project is archived error. +func IsErrProjectCannotBelongToAPseudoParentProject(err error) bool { + _, ok := err.(*ErrProjectCannotBelongToAPseudoParentProject) return ok } -func (err *ErrProjectCannotBelongToAPseudoNamespace) Error() string { - return fmt.Sprintf("Project cannot belong to a pseudo namespace [ProjectID: %d, NamespaceID: %d]", err.ProjectID, err.NamespaceID) +func (err *ErrProjectCannotBelongToAPseudoParentProject) Error() string { + return fmt.Sprintf("Project cannot belong to a pseudo parent project [ProjectID: %d, ParentProjectID: %d]", err.ProjectID, err.ParentProjectID) } -// ErrCodeProjectCannotBelongToAPseudoNamespace holds the unique world-error code of this error -const ErrCodeProjectCannotBelongToAPseudoNamespace = 3009 +// ErrCodeProjectCannotBelongToAPseudoParentProject holds the unique world-error code of this error +const ErrCodeProjectCannotBelongToAPseudoParentProject = 3009 // HTTPError holds the http error description -func (err *ErrProjectCannotBelongToAPseudoNamespace) HTTPError() web.HTTPError { +func (err *ErrProjectCannotBelongToAPseudoParentProject) HTTPError() web.HTTPError { return web.HTTPError{ HTTPCode: http.StatusPreconditionFailed, - Code: ErrCodeProjectCannotBelongToAPseudoNamespace, - Message: "This project cannot belong a dynamically generated namespace.", + Code: ErrCodeProjectCannotBelongToAPseudoParentProject, + Message: "This project cannot belong a dynamically generated project.", } } -// ErrProjectMustBelongToANamespace represents an error where a project must belong to a namespace -type ErrProjectMustBelongToANamespace struct { - ProjectID int64 - NamespaceID int64 -} - -// IsErrProjectMustBelongToANamespace checks if an error is a project must belong to a namespace error. -func IsErrProjectMustBelongToANamespace(err error) bool { - _, ok := err.(*ErrProjectMustBelongToANamespace) - return ok -} - -func (err *ErrProjectMustBelongToANamespace) Error() string { - return fmt.Sprintf("Project must belong to a namespace [ProjectID: %d, NamespaceID: %d]", err.ProjectID, err.NamespaceID) -} - -// ErrCodeProjectMustBelongToANamespace holds the unique world-error code of this error -const ErrCodeProjectMustBelongToANamespace = 3010 - -// HTTPError holds the http error description -func (err *ErrProjectMustBelongToANamespace) HTTPError() web.HTTPError { - return web.HTTPError{ - HTTPCode: http.StatusPreconditionFailed, - Code: ErrCodeProjectMustBelongToANamespace, - Message: "This project must belong to a namespace.", - } -} - -// ================ -// Project task errors -// ================ +// ============== +// Project errors +// ============== // ErrTaskCannotBeEmpty represents a "ErrProjectDoesNotExist" kind of error. Used if the project does not exist. type ErrTaskCannotBeEmpty struct{} @@ -875,176 +847,6 @@ func (err ErrUserAlreadyAssigned) HTTPError() web.HTTPError { } } -// ================= -// Namespace errors -// ================= - -// ErrNamespaceDoesNotExist represents a "ErrNamespaceDoesNotExist" kind of error. Used if the namespace does not exist. -type ErrNamespaceDoesNotExist struct { - ID int64 -} - -// IsErrNamespaceDoesNotExist checks if an error is a ErrNamespaceDoesNotExist. -func IsErrNamespaceDoesNotExist(err error) bool { - _, ok := err.(ErrNamespaceDoesNotExist) - return ok -} - -func (err ErrNamespaceDoesNotExist) Error() string { - return fmt.Sprintf("Namespace does not exist [ID: %d]", err.ID) -} - -// ErrCodeNamespaceDoesNotExist holds the unique world-error code of this error -const ErrCodeNamespaceDoesNotExist = 5001 - -// HTTPError holds the http error description -func (err ErrNamespaceDoesNotExist) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeNamespaceDoesNotExist, Message: "Namespace not found."} -} - -// ErrUserDoesNotHaveAccessToNamespace represents an error, where the user is not the owner of that namespace (used i.e. when deleting a namespace) -type ErrUserDoesNotHaveAccessToNamespace struct { - NamespaceID int64 - UserID int64 -} - -// IsErrUserDoesNotHaveAccessToNamespace checks if an error is a ErrNamespaceDoesNotExist. -func IsErrUserDoesNotHaveAccessToNamespace(err error) bool { - _, ok := err.(ErrUserDoesNotHaveAccessToNamespace) - return ok -} - -func (err ErrUserDoesNotHaveAccessToNamespace) Error() string { - return fmt.Sprintf("User does not have access to the namespace [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID) -} - -// ErrCodeUserDoesNotHaveAccessToNamespace holds the unique world-error code of this error -const ErrCodeUserDoesNotHaveAccessToNamespace = 5003 - -// HTTPError holds the http error description -func (err ErrUserDoesNotHaveAccessToNamespace) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrCodeUserDoesNotHaveAccessToNamespace, Message: "This user does not have access to the namespace."} -} - -// ErrNamespaceNameCannotBeEmpty represents an error, where a namespace name is empty. -type ErrNamespaceNameCannotBeEmpty struct { - NamespaceID int64 - UserID int64 -} - -// IsErrNamespaceNameCannotBeEmpty checks if an error is a ErrNamespaceDoesNotExist. -func IsErrNamespaceNameCannotBeEmpty(err error) bool { - _, ok := err.(ErrNamespaceNameCannotBeEmpty) - return ok -} - -func (err ErrNamespaceNameCannotBeEmpty) Error() string { - return fmt.Sprintf("Namespace name cannot be empty [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID) -} - -// ErrCodeNamespaceNameCannotBeEmpty holds the unique world-error code of this error -const ErrCodeNamespaceNameCannotBeEmpty = 5006 - -// HTTPError holds the http error description -func (err ErrNamespaceNameCannotBeEmpty) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeNamespaceNameCannotBeEmpty, Message: "The namespace name cannot be empty."} -} - -// ErrNeedToHaveNamespaceReadAccess represents an error, where the user is not the owner of that namespace (used i.e. when deleting a namespace) -type ErrNeedToHaveNamespaceReadAccess struct { - NamespaceID int64 - UserID int64 -} - -// IsErrNeedToHaveNamespaceReadAccess checks if an error is a ErrNamespaceDoesNotExist. -func IsErrNeedToHaveNamespaceReadAccess(err error) bool { - _, ok := err.(ErrNeedToHaveNamespaceReadAccess) - return ok -} - -func (err ErrNeedToHaveNamespaceReadAccess) Error() string { - return fmt.Sprintf("User does not have access to that namespace [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID) -} - -// ErrCodeNeedToHaveNamespaceReadAccess holds the unique world-error code of this error -const ErrCodeNeedToHaveNamespaceReadAccess = 5009 - -// HTTPError holds the http error description -func (err ErrNeedToHaveNamespaceReadAccess) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrCodeNeedToHaveNamespaceReadAccess, Message: "You need to have namespace read access to do this."} -} - -// ErrTeamDoesNotHaveAccessToNamespace represents an error, where the Team is not the owner of that namespace (used i.e. when deleting a namespace) -type ErrTeamDoesNotHaveAccessToNamespace struct { - NamespaceID int64 - TeamID int64 -} - -// IsErrTeamDoesNotHaveAccessToNamespace checks if an error is a ErrNamespaceDoesNotExist. -func IsErrTeamDoesNotHaveAccessToNamespace(err error) bool { - _, ok := err.(ErrTeamDoesNotHaveAccessToNamespace) - return ok -} - -func (err ErrTeamDoesNotHaveAccessToNamespace) Error() string { - return fmt.Sprintf("Team does not have access to that namespace [NamespaceID: %d, TeamID: %d]", err.NamespaceID, err.TeamID) -} - -// ErrCodeTeamDoesNotHaveAccessToNamespace holds the unique world-error code of this error -const ErrCodeTeamDoesNotHaveAccessToNamespace = 5010 - -// HTTPError holds the http error description -func (err ErrTeamDoesNotHaveAccessToNamespace) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrCodeTeamDoesNotHaveAccessToNamespace, Message: "You need to have access to this namespace to do this."} -} - -// ErrUserAlreadyHasNamespaceAccess represents an error where a user already has access to a namespace -type ErrUserAlreadyHasNamespaceAccess struct { - UserID int64 - NamespaceID int64 -} - -// IsErrUserAlreadyHasNamespaceAccess checks if an error is ErrUserAlreadyHasNamespaceAccess. -func IsErrUserAlreadyHasNamespaceAccess(err error) bool { - _, ok := err.(ErrUserAlreadyHasNamespaceAccess) - return ok -} - -func (err ErrUserAlreadyHasNamespaceAccess) Error() string { - return fmt.Sprintf("User already has access to that namespace. [User ID: %d, Namespace ID: %d]", err.UserID, err.NamespaceID) -} - -// ErrCodeUserAlreadyHasNamespaceAccess holds the unique world-error code of this error -const ErrCodeUserAlreadyHasNamespaceAccess = 5011 - -// HTTPError holds the http error description -func (err ErrUserAlreadyHasNamespaceAccess) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusConflict, Code: ErrCodeUserAlreadyHasNamespaceAccess, Message: "This user already has access to this namespace."} -} - -// ErrNamespaceIsArchived represents an error where a namespace is archived -type ErrNamespaceIsArchived struct { - NamespaceID int64 -} - -// IsErrNamespaceIsArchived checks if an error is a . -func IsErrNamespaceIsArchived(err error) bool { - _, ok := err.(ErrNamespaceIsArchived) - return ok -} - -func (err ErrNamespaceIsArchived) Error() string { - return fmt.Sprintf("Namespace is archived [NamespaceID: %d]", err.NamespaceID) -} - -// ErrCodeNamespaceIsArchived holds the unique world-error code of this error -const ErrCodeNamespaceIsArchived = 5012 - -// HTTPError holds the http error description -func (err ErrNamespaceIsArchived) HTTPError() web.HTTPError { - return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeNamespaceIsArchived, Message: "This namespaces is archived. Editing or creating new projects is not possible."} -} - // ============ // Team errors // ============ @@ -1054,7 +856,7 @@ type ErrTeamNameCannotBeEmpty struct { TeamID int64 } -// IsErrTeamNameCannotBeEmpty checks if an error is a ErrNamespaceDoesNotExist. +// IsErrTeamNameCannotBeEmpty checks if an error is a ErrTeamNameCannotBeEmpty. func IsErrTeamNameCannotBeEmpty(err error) bool { _, ok := err.(ErrTeamNameCannotBeEmpty) return ok @@ -1095,7 +897,7 @@ func (err ErrTeamDoesNotExist) HTTPError() web.HTTPError { return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeTeamDoesNotExist, Message: "This team does not exist."} } -// ErrTeamAlreadyHasAccess represents an error where a team already has access to a project/namespace +// ErrTeamAlreadyHasAccess represents an error where a team already has access to a project type ErrTeamAlreadyHasAccess struct { TeamID int64 ID int64 @@ -1195,7 +997,7 @@ func (err ErrTeamDoesNotHaveAccessToProject) HTTPError() web.HTTPError { // User <-> Project errors // ==================== -// ErrUserAlreadyHasAccess represents an error where a user already has access to a project/namespace +// ErrUserAlreadyHasAccess represents an error where a user already has access to a project type ErrUserAlreadyHasAccess struct { UserID int64 ProjectID int64 diff --git a/pkg/models/events.go b/pkg/models/events.go index cc0ad8e6a..4838e1114 100644 --- a/pkg/models/events.go +++ b/pkg/models/events.go @@ -104,43 +104,6 @@ func (t *TaskCommentUpdatedEvent) Name() string { return "task.comment.edited" } -////////////////////// -// Namespace Events // -////////////////////// - -// NamespaceCreatedEvent represents an event where a namespace has been created -type NamespaceCreatedEvent struct { - Namespace *Namespace - Doer web.Auth -} - -// Name defines the name for NamespaceCreatedEvent -func (n *NamespaceCreatedEvent) Name() string { - return "namespace.created" -} - -// NamespaceUpdatedEvent represents an event where a namespace has been updated -type NamespaceUpdatedEvent struct { - Namespace *Namespace - Doer web.Auth -} - -// Name defines the name for NamespaceUpdatedEvent -func (n *NamespaceUpdatedEvent) Name() string { - return "namespace.updated" -} - -// NamespaceDeletedEvent represents a NamespaceDeletedEvent event -type NamespaceDeletedEvent struct { - Namespace *Namespace - Doer web.Auth -} - -// TopicName defines the name for NamespaceDeletedEvent -func (t *NamespaceDeletedEvent) Name() string { - return "namespace.deleted" -} - ///////////////// // Project Events // ///////////////// @@ -206,30 +169,6 @@ func (l *ProjectSharedWithTeamEvent) Name() string { return "project.shared.team" } -// NamespaceSharedWithUserEvent represents an event where a namespace has been shared with a user -type NamespaceSharedWithUserEvent struct { - Namespace *Namespace - User *user.User - Doer web.Auth -} - -// Name defines the name for NamespaceSharedWithUserEvent -func (n *NamespaceSharedWithUserEvent) Name() string { - return "namespace.shared.user" -} - -// NamespaceSharedWithTeamEvent represents an event where a namespace has been shared with a team -type NamespaceSharedWithTeamEvent struct { - Namespace *Namespace - Team *Team - Doer web.Auth -} - -// Name defines the name for NamespaceSharedWithTeamEvent -func (n *NamespaceSharedWithTeamEvent) Name() string { - return "namespace.shared.team" -} - ///////////////// // Team Events // ///////////////// diff --git a/pkg/models/export.go b/pkg/models/export.go index 1ae87881d..54ff0abce 100644 --- a/pkg/models/export.go +++ b/pkg/models/export.go @@ -57,12 +57,12 @@ func ExportUserData(s *xorm.Session, u *user.User) (err error) { defer dumpWriter.Close() // Get the data - err = exportProjectsAndTasks(s, u, dumpWriter) + taskIDs, err := exportProjectsAndTasks(s, u, dumpWriter) if err != nil { return err } // Task attachment files - err = exportTaskAttachments(s, u, dumpWriter) + err = exportTaskAttachments(s, u, dumpWriter, taskIDs) if err != nil { return err } @@ -121,51 +121,35 @@ func ExportUserData(s *xorm.Session, u *user.User) (err error) { }) } -func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (err error) { - - namspaces, _, _, err := (&Namespace{IsArchived: true}).ReadAll(s, u, "", -1, 0) - if err != nil { - return err - } - - namespaceIDs := []int64{} - namespaces := []*NamespaceWithProjectsAndTasks{} - projectMap := make(map[int64]*ProjectWithTasksAndBuckets) - projectIDs := []int64{} - for _, n := range namspaces.([]*NamespaceWithProjects) { - if n.ID < 1 { - // Don't include filters - continue - } - - nn := &NamespaceWithProjectsAndTasks{ - Namespace: n.Namespace, - Projects: []*ProjectWithTasksAndBuckets{}, - } - - for _, l := range n.Projects { - ll := &ProjectWithTasksAndBuckets{ - Project: *l, - BackgroundFileID: l.BackgroundFileID, - Tasks: []*TaskWithComments{}, - } - nn.Projects = append(nn.Projects, ll) - projectMap[l.ID] = ll - projectIDs = append(projectIDs, l.ID) - } - - namespaceIDs = append(namespaceIDs, n.ID) - namespaces = append(namespaces, nn) - } - - if len(namespaceIDs) == 0 { - return nil - } +func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (taskIDs []int64, err error) { // Get all projects - projects, err := getProjectsForNamespaces(s, namespaceIDs, true) + rawProjectsMap, _, _, err := getRawProjectsForUser( + s, + &projectOptions{ + search: "", + user: u, + page: 0, + perPage: -1, + getArchived: true, + }) if err != nil { - return err + return taskIDs, err + } + + if len(rawProjectsMap) == 0 { + return + } + + projects := []*Project{} + projectsMap := make(map[int64]*ProjectWithTasksAndBuckets, len(rawProjectsMap)) + projectIDs := []int64{} + for _, p := range rawProjectsMap { + projects = append(projects, p) + projectsMap[p.ID] = &ProjectWithTasksAndBuckets{ + Project: *p, + } + projectIDs = append(projectIDs, p.ID) } tasks, _, _, err := getTasksForProjects(s, projects, u, &taskOptions{ @@ -173,7 +157,7 @@ func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (err perPage: -1, }) if err != nil { - return err + return taskIDs, err } taskMap := make(map[int64]*TaskWithComments, len(tasks)) @@ -181,11 +165,12 @@ func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (err taskMap[t.ID] = &TaskWithComments{ Task: *t, } - if _, exists := projectMap[t.ProjectID]; !exists { + if _, exists := projectsMap[t.ProjectID]; !exists { log.Debugf("[User Data Export] Project %d does not exist for task %d, omitting", t.ProjectID, t.ID) continue } - projectMap[t.ProjectID].Tasks = append(projectMap[t.ProjectID].Tasks, taskMap[t.ID]) + projectsMap[t.ProjectID].Tasks = append(projectsMap[t.ProjectID].Tasks, taskMap[t.ID]) + taskIDs = append(taskIDs, t.ID) } comments := []*TaskComment{} @@ -212,43 +197,22 @@ func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (err } for _, b := range buckets { - if _, exists := projectMap[b.ProjectID]; !exists { + if _, exists := projectsMap[b.ProjectID]; !exists { log.Debugf("[User Data Export] Project %d does not exist for bucket %d, omitting", b.ProjectID, b.ID) continue } - projectMap[b.ProjectID].Buckets = append(projectMap[b.ProjectID].Buckets, b) + projectsMap[b.ProjectID].Buckets = append(projectsMap[b.ProjectID].Buckets, b) } - data, err := json.Marshal(namespaces) + data, err := json.Marshal(projects) if err != nil { - return err + return taskIDs, err } - return utils.WriteBytesToZip("data.json", data, wr) + return taskIDs, utils.WriteBytesToZip("data.json", data, wr) } -func exportTaskAttachments(s *xorm.Session, u *user.User, wr *zip.Writer) (err error) { - projects, _, _, err := getRawProjectsForUser( - s, - &projectOptions{ - user: u, - page: -1, - }, - ) - if err != nil { - return err - } - - tasks, _, _, err := getRawTasksForProjects(s, projects, u, &taskOptions{page: -1}) - if err != nil { - return err - } - - taskIDs := []int64{} - for _, t := range tasks { - taskIDs = append(taskIDs, t.ID) - } - +func exportTaskAttachments(s *xorm.Session, u *user.User, wr *zip.Writer, taskIDs []int64) (err error) { tas, err := getTaskAttachmentsByTaskIDs(s, taskIDs) if err != nil { return err diff --git a/pkg/models/listeners.go b/pkg/models/listeners.go index 7457d0bd0..0f2a52fbd 100644 --- a/pkg/models/listeners.go +++ b/pkg/models/listeners.go @@ -35,8 +35,6 @@ import ( func RegisterListeners() { events.RegisterListener((&ProjectCreatedEvent{}).Name(), &IncreaseProjectCounter{}) events.RegisterListener((&ProjectDeletedEvent{}).Name(), &DecreaseProjectCounter{}) - events.RegisterListener((&NamespaceCreatedEvent{}).Name(), &IncreaseNamespaceCounter{}) - events.RegisterListener((&NamespaceDeletedEvent{}).Name(), &DecreaseNamespaceCounter{}) events.RegisterListener((&TaskCreatedEvent{}).Name(), &IncreaseTaskCounter{}) events.RegisterListener((&TaskDeletedEvent{}).Name(), &DecreaseTaskCounter{}) events.RegisterListener((&TeamDeletedEvent{}).Name(), &DecreaseTeamCounter{}) @@ -478,37 +476,6 @@ func (s *SendProjectCreatedNotification) Handle(msg *message.Message) (err error return nil } -////// -// Namespace events - -// IncreaseNamespaceCounter represents a listener -type IncreaseNamespaceCounter struct { -} - -// Name defines the name for the IncreaseNamespaceCounter listener -func (s *IncreaseNamespaceCounter) Name() string { - return "namespace.counter.increase" -} - -// Hanlde is executed when the event IncreaseNamespaceCounter listens on is fired -func (s *IncreaseNamespaceCounter) Handle(msg *message.Message) (err error) { - return keyvalue.IncrBy(metrics.NamespaceCountKey, 1) -} - -// DecreaseNamespaceCounter represents a listener -type DecreaseNamespaceCounter struct { -} - -// Name defines the name for the DecreaseNamespaceCounter listener -func (s *DecreaseNamespaceCounter) Name() string { - return "namespace.counter.decrease" -} - -// Hanlde is executed when the event DecreaseNamespaceCounter listens on is fired -func (s *DecreaseNamespaceCounter) Handle(msg *message.Message) (err error) { - return keyvalue.DecrBy(metrics.NamespaceCountKey, 1) -} - /////// // Team Events diff --git a/pkg/models/models.go b/pkg/models/models.go index 66191e1f0..56186f3d3 100644 --- a/pkg/models/models.go +++ b/pkg/models/models.go @@ -44,10 +44,7 @@ func GetTables() []interface{} { &Team{}, &TeamMember{}, &TeamProject{}, - &TeamNamespace{}, - &Namespace{}, &ProjectUser{}, - &NamespaceUser{}, &TaskAssginee{}, &Label{}, &LabelTask{}, diff --git a/pkg/models/prject.go b/pkg/models/prject.go index 6ada13fcf..937c08448 100644 --- a/pkg/models/prject.go +++ b/pkg/models/prject.go @@ -37,7 +37,7 @@ import ( type Project struct { // The unique, numeric id of this project. ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"project"` - // The title of the project. You'll see this in the namespace overview. + // The title of the project. You'll see this in the overview. Title string `xorm:"varchar(250) not null" json:"title" valid:"required,runelength(1|250)" minLength:"1" maxLength:"250"` // The description of the project. Description string `xorm:"longtext null" json:"description"` @@ -64,7 +64,7 @@ type Project struct { // Contains a very small version of the project background to use as a blurry preview until the actual background is loaded. Check out https://blurha.sh/ to learn how it works. BackgroundBlurHash string `xorm:"varchar(50) null" json:"background_blur_hash"` - // True if a project is a favorite. Favorite projects show up in a separate namespace. This value depends on the user making the call to the api. + // True if a project is a favorite. Favorite projects show up in a separate parent project. This value depends on the user making the call to the api. IsFavorite bool `xorm:"-" json:"is_favorite"` // The subscription status for the user reading this project. You can only read this property, use the subscription endpoints to modify it. @@ -114,7 +114,7 @@ var SharedProjectsPseudoProject = &Project{ Updated: time.Now(), } -// FavoriteProjectsPseudoProject is a pseudo namespace used to hold favorite projects and tasks +// FavoriteProjectsPseudoProject is a pseudo parent project used to hold favorite projects and tasks var FavoriteProjectsPseudoProject = &Project{ ID: -2, Title: "Favorites", @@ -123,7 +123,7 @@ var FavoriteProjectsPseudoProject = &Project{ Updated: time.Now(), } -// SavedFiltersPseudoProject is a pseudo namespace used to hold saved filters +// SavedFiltersPseudoProject is a pseudo parent project used to hold saved filters var SavedFiltersPseudoProject = &Project{ ID: -3, Title: "Filters", @@ -267,13 +267,11 @@ func (p *Project) ReadOne(s *xorm.Session, a web.Auth) (err error) { if err != nil { return err } - // Check if the namespace is archived and set the namespace to archived if it is not already archived individually. + + // Check if the project is archived and set it to archived if it is not already archived individually. if !p.IsArchived { err = p.CheckIsArchived(s) if err != nil { - if !IsErrNamespaceIsArchived(err) && !IsErrProjectIsArchived(err) { - return - } p.IsArchived = true } } @@ -561,7 +559,7 @@ func addProjectDetails(s *xorm.Session, projects map[int64]*Project, a web.Auth) return } -// CheckIsArchived returns an ErrProjectIsArchived or ErrNamespaceIsArchived if the project or any of its parent projects is archived. +// CheckIsArchived returns an ErrProjectIsArchived if the project or any of its parent projects is archived. func (p *Project) CheckIsArchived(s *xorm.Session) (err error) { // When creating a new project, we check if the parent is archived if p.ID == 0 { @@ -569,14 +567,14 @@ func (p *Project) CheckIsArchived(s *xorm.Session) (err error) { return p.CheckIsArchived(s) } - p, err := GetProjectSimpleByID(s, p.ID) + project, err := GetProjectSimpleByID(s, p.ID) if err != nil { return err } // TODO: parent project - if p.IsArchived { + if project.IsArchived { return ErrProjectIsArchived{ProjectID: p.ID} } @@ -585,7 +583,7 @@ func (p *Project) CheckIsArchived(s *xorm.Session) (err error) { func checkProjectBeforeUpdateOrDelete(s *xorm.Session, project *Project) error { if project.ParentProjectID < 0 { - return &ErrProjectCannotBelongToAPseudoNamespace{ProjectID: project.ID, NamespaceID: project.ParentProjectID} + return &ErrProjectCannotBelongToAPseudoParentProject{ProjectID: project.ID, ParentProjectID: project.ParentProjectID} } // Check if the parent project exists diff --git a/pkg/models/project_duplicate.go b/pkg/models/project_duplicate.go index 3307935af..f4f8d99ad 100644 --- a/pkg/models/project_duplicate.go +++ b/pkg/models/project_duplicate.go @@ -28,8 +28,8 @@ import ( type ProjectDuplicate struct { // The project id of the project to duplicate ProjectID int64 `json:"-" param:"projectid"` - // The target namespace ID - NamespaceID int64 `json:"namespace_id,omitempty"` + // The target parent project + ParentProjectID int64 `json:"parent_project_id,omitempty"` // The copied project Project *Project `json:",omitempty"` @@ -47,23 +47,27 @@ func (ld *ProjectDuplicate) CanCreate(s *xorm.Session, a web.Auth) (canCreate bo return canRead, err } - // Namespace exists + user has write access to is (-> can create new projects) - ld.Project.NamespaceID = ld.NamespaceID - return ld.Project.CanCreate(s, a) + if ld.ParentProjectID == 0 { // no parent project + return canRead, err + } + + // Parent project exists + user has write access to is (-> can create new projects) + parent := &Project{ID: ld.ParentProjectID} + return parent.CanCreate(s, a) } // Create duplicates a project // @Summary Duplicate an existing project -// @Description Copies the project, tasks, files, kanban data, assignees, comments, attachments, lables, relations, backgrounds, user/team rights and link shares from one project to a new namespace. The user needs read access in the project and write access in the namespace of the new project. +// @Description Copies the project, tasks, files, kanban data, assignees, comments, attachments, lables, relations, backgrounds, user/team rights and link shares from one project to a new one. The user needs read access in the project and write access in the parent of the new project. // @tags project // @Accept json // @Produce json // @Security JWTKeyAuth // @Param projectID path int true "The project ID to duplicate" -// @Param project body models.ProjectDuplicate true "The target namespace which should hold the copied project." +// @Param project body models.ProjectDuplicate true "The target parent project which should hold the copied project." // @Success 201 {object} models.ProjectDuplicate "The created project." // @Failure 400 {object} web.HTTPError "Invalid project duplicate object provided." -// @Failure 403 {object} web.HTTPError "The user does not have access to the project or namespace" +// @Failure 403 {object} web.HTTPError "The user does not have access to the project or its parent." // @Failure 500 {object} models.Message "Internal error" // @Router /projects/{projectID}/duplicate [put] // @@ -153,7 +157,7 @@ func (ld *ProjectDuplicate) Create(s *xorm.Session, doer web.Auth) (err error) { } // Rights / Shares - // To keep it simple(r) we will only copy rights which are directly used with the project, no namespace changes. + // To keep it simple(r) we will only copy rights which are directly used with the project, not the parent users := []*ProjectUser{} err = s.Where("project_id = ?", ld.ProjectID).Find(&users) if err != nil { diff --git a/pkg/models/rights.go b/pkg/models/rights.go index 67f3585ec..ddfdbc22e 100644 --- a/pkg/models/rights.go +++ b/pkg/models/rights.go @@ -16,7 +16,7 @@ package models -// Right defines the rights users/teams can have for projects/namespaces +// Right defines the rights users/teams can have for projects type Right int // define unknown right @@ -30,7 +30,7 @@ const ( RightRead Right = iota // Can write in a like projects and tasks. Cannot create new projects. RightWrite - // Can manage a project/namespace, can do everything + // Can manage a project, can do everything RightAdmin ) diff --git a/pkg/models/saved_filters.go b/pkg/models/saved_filters.go index 91db28214..b76a003db 100644 --- a/pkg/models/saved_filters.go +++ b/pkg/models/saved_filters.go @@ -39,7 +39,7 @@ type SavedFilter struct { // The user who owns this filter Owner *user.User `xorm:"-" json:"owner" valid:"-"` - // True if the filter is a favorite. Favorite filters show up in a separate namespace together with favorite projects. + // True if the filter is a favorite. Favorite filters show up in a separate parent project together with favorite projects. IsFavorite bool `xorm:"default false" json:"is_favorite"` // A timestamp when this filter was created. You cannot change this value. @@ -95,14 +95,14 @@ func getSavedFiltersForUser(s *xorm.Session, auth web.Auth) (filters []*SavedFil func (sf *SavedFilter) toProject() *Project { return &Project{ - ID: getProjectIDFromSavedFilterID(sf.ID), - Title: sf.Title, - Description: sf.Description, - IsFavorite: sf.IsFavorite, - Created: sf.Created, - Updated: sf.Updated, - Owner: sf.Owner, - NamespaceID: SavedFiltersPseudoProject.ID, + ID: getProjectIDFromSavedFilterID(sf.ID), + Title: sf.Title, + Description: sf.Description, + IsFavorite: sf.IsFavorite, + Created: sf.Created, + Updated: sf.Updated, + Owner: sf.Owner, + ParentProjectID: SavedFiltersPseudoProject.ID, } } diff --git a/pkg/models/subscription.go b/pkg/models/subscription.go index 51aac4874..e646161c3 100644 --- a/pkg/models/subscription.go +++ b/pkg/models/subscription.go @@ -30,16 +30,15 @@ import ( type SubscriptionEntityType int const ( - SubscriptionEntityUnknown = iota - SubscriptionEntityNamespace + SubscriptionEntityUnknown = iota + SubscriptionEntityNamespace // Kept even though not used anymore since we don't want to manually change all ids SubscriptionEntityProject SubscriptionEntityTask ) const ( - entityNamespace = `namespace` - entityProject = `project` - entityTask = `task` + entityProject = `project` + entityTask = `task` ) // Subscription represents a subscription for an entity @@ -70,8 +69,6 @@ func (sb *Subscription) TableName() string { func getEntityTypeFromString(entityType string) SubscriptionEntityType { switch entityType { - case entityNamespace: - return SubscriptionEntityNamespace case entityProject: return SubscriptionEntityProject case entityTask: @@ -84,8 +81,6 @@ func getEntityTypeFromString(entityType string) SubscriptionEntityType { // String returns a human-readable string of an entity func (et SubscriptionEntityType) String() string { switch et { - case SubscriptionEntityNamespace: - return entityNamespace case SubscriptionEntityProject: return entityProject case SubscriptionEntityTask: @@ -96,8 +91,7 @@ func (et SubscriptionEntityType) String() string { } func (et SubscriptionEntityType) validate() error { - if et == SubscriptionEntityNamespace || - et == SubscriptionEntityProject || + if et == SubscriptionEntityProject || et == SubscriptionEntityTask { return nil } @@ -112,7 +106,7 @@ func (et SubscriptionEntityType) validate() error { // @Accept json // @Produce json // @Security JWTKeyAuth -// @Param entity path string true "The entity the user subscribes to. Can be either `namespace`, `project` or `task`." +// @Param entity path string true "The entity the user subscribes to. Can be either `project` or `task`." // @Param entityID path string true "The numeric id of the entity to subscribe to." // @Success 201 {object} models.Subscription "The subscription" // @Failure 403 {object} web.HTTPError "The user does not have access to subscribe to this entity." @@ -153,7 +147,7 @@ func (sb *Subscription) Create(s *xorm.Session, auth web.Auth) (err error) { // @Accept json // @Produce json // @Security JWTKeyAuth -// @Param entity path string true "The entity the user subscribed to. Can be either `namespace`, `project` or `task`." +// @Param entity path string true "The entity the user subscribed to. Can be either `project` or `task`." // @Param entityID path string true "The numeric id of the subscribed entity to." // @Success 200 {object} models.Subscription "The subscription" // @Failure 403 {object} web.HTTPError "The user does not have access to subscribe to this entity." @@ -170,45 +164,20 @@ func (sb *Subscription) Delete(s *xorm.Session, auth web.Auth) (err error) { } func getSubscriberCondForEntity(entityType SubscriptionEntityType, entityID int64) (cond builder.Cond) { - if entityType == SubscriptionEntityNamespace { - cond = builder.And( - builder.Eq{"entity_id": entityID}, - builder.Eq{"entity_type": SubscriptionEntityNamespace}, - ) - } - if entityType == SubscriptionEntityProject { - cond = builder.Or( - builder.And( - builder.Eq{"entity_id": entityID}, - builder.Eq{"entity_type": SubscriptionEntityProject}, - ), - builder.And( - builder.Eq{"entity_id": builder. - Select("namespace_id"). - From("projects"). - Where(builder.Eq{"id": entityID}), - }, - builder.Eq{"entity_type": SubscriptionEntityNamespace}, - ), + return builder.And( + builder.Eq{"entity_id": entityID}, + builder.Eq{"entity_type": SubscriptionEntityProject}, ) + // TODO: parent? } if entityType == SubscriptionEntityTask { - cond = builder.Or( + return builder.Or( builder.And( builder.Eq{"entity_id": entityID}, builder.Eq{"entity_type": SubscriptionEntityTask}, ), - builder.And( - builder.Eq{"entity_id": builder. - Select("namespace_id"). - From("projects"). - Join("INNER", "tasks", "projects.id = tasks.project_id"). - Where(builder.Eq{"tasks.id": entityID}), - }, - builder.Eq{"entity_type": SubscriptionEntityNamespace}, - ), builder.And( builder.Eq{"entity_id": builder. Select("project_id"). @@ -225,8 +194,8 @@ func getSubscriberCondForEntity(entityType SubscriptionEntityType, entityID int6 // GetSubscription returns a matching subscription for an entity and user. // It will return the next parent of a subscription. That means for tasks, it will first look for a subscription for -// that task, if there is none it will look for a subscription on the project the task belongs to and if that also -// doesn't exist it will check for a subscription for the namespace the project is belonging to. +// that task, if there is none it will look for a subscription on the project the task belongs to. +// TODO: check parent projects func GetSubscription(s *xorm.Session, entityType SubscriptionEntityType, entityID int64, a web.Auth) (subscription *Subscription, err error) { subs, err := GetSubscriptions(s, entityType, []int64{entityID}, a) if err != nil || len(subs) == 0 { diff --git a/pkg/models/subscription_rights.go b/pkg/models/subscription_rights.go index 88f45438a..123dd47b2 100644 --- a/pkg/models/subscription_rights.go +++ b/pkg/models/subscription_rights.go @@ -30,9 +30,6 @@ func (sb *Subscription) CanCreate(s *xorm.Session, a web.Auth) (can bool, err er sb.EntityType = getEntityTypeFromString(sb.Entity) switch sb.EntityType { - case SubscriptionEntityNamespace: - n := &Namespace{ID: sb.EntityID} - can, _, err = n.CanRead(s, a) case SubscriptionEntityProject: l := &Project{ID: sb.EntityID} can, _, err = l.CanRead(s, a) diff --git a/pkg/models/task_collection_filter.go b/pkg/models/task_collection_filter.go index 4a4dd1ccc..06f75db97 100644 --- a/pkg/models/task_collection_filter.go +++ b/pkg/models/task_collection_filter.go @@ -237,24 +237,6 @@ func getNativeValueForTaskField(fieldName string, comparator taskFilterComparato realFieldName := strings.ReplaceAll(strcase.ToCamel(fieldName), "Id", "ID") - if realFieldName == "Namespace" { - if comparator == taskFilterComparatorIn { - vals := strings.Split(value, ",") - valueSlice := []interface{}{} - for _, val := range vals { - v, err := strconv.ParseInt(val, 10, 64) - if err != nil { - return nil, nil, err - } - valueSlice = append(valueSlice, v) - } - return nil, valueSlice, nil - } - - nativeValue, err = strconv.ParseInt(value, 10, 64) - return - } - if realFieldName == "Assignees" { vals := strings.Split(value, ",") valueSlice := append([]string{}, vals...) diff --git a/pkg/models/teams.go b/pkg/models/teams.go index 12a39095f..db439de81 100644 --- a/pkg/models/teams.go +++ b/pkg/models/teams.go @@ -241,7 +241,7 @@ func (t *Team) ReadAll(s *xorm.Session, a web.Auth, search string, page int, per // Create is the handler to create a team // @Summary Creates a new team -// @Description Creates a new team in a given namespace. The user needs write-access to the namespace. +// @Description Creates a new team. // @tags team // @Accept json // @Produce json @@ -307,12 +307,6 @@ func (t *Team) Delete(s *xorm.Session, a web.Auth) (err error) { return } - // Delete team <-> namespace relations - _, err = s.Where("team_id = ?", t.ID).Delete(&TeamNamespace{}) - if err != nil { - return - } - // Delete team <-> projects relations _, err = s.Where("team_id = ?", t.ID).Delete(&TeamProject{}) if err != nil { diff --git a/pkg/models/unit_tests.go b/pkg/models/unit_tests.go index ce9b80714..3dd56dad3 100644 --- a/pkg/models/unit_tests.go +++ b/pkg/models/unit_tests.go @@ -48,7 +48,6 @@ func SetupTests() { "labels", "link_shares", "projects", - "namespaces", "task_assignees", "task_attachments", "task_comments", @@ -57,12 +56,10 @@ func SetupTests() { "tasks", "team_projects", "team_members", - "team_namespaces", "teams", "users", "user_tokens", "users_projects", - "users_namespaces", "buckets", "saved_filters", "subscriptions", diff --git a/pkg/models/user_project.go b/pkg/models/user_project.go index a929541ef..848aaaa1e 100644 --- a/pkg/models/user_project.go +++ b/pkg/models/user_project.go @@ -22,14 +22,11 @@ import ( "xorm.io/xorm" ) -// ProjectUIDs hold all kinds of user IDs from accounts who have somehow access to a project +// ProjectUIDs hold all kinds of user IDs from accounts who have access to a project type ProjectUIDs struct { - ProjectOwnerID int64 `xorm:"projectOwner"` - NamespaceUserID int64 `xorm:"unID"` - ProjectUserID int64 `xorm:"ulID"` - NamespaceOwnerUserID int64 `xorm:"nOwner"` - TeamNamespaceUserID int64 `xorm:"tnUID"` - TeamProjectUserID int64 `xorm:"tlUID"` + ProjectOwnerID int64 `xorm:"projectOwner"` + ProjectUserID int64 `xorm:"ulID"` + TeamProjectUserID int64 `xorm:"tlUID"` } // ListUsersFromProject returns a list with all users who have access to a project, regardless of the method which gave them access @@ -39,39 +36,26 @@ func ListUsersFromProject(s *xorm.Session, l *Project, search string) (users []* err = s. Select(`l.owner_id as projectOwner, - un.user_id as unID, ul.user_id as ulID, - n.owner_id as nOwner, - tm.user_id as tnUID, tm2.user_id as tlUID`). Table("projects"). Alias("l"). // User stuff - Join("LEFT", []string{"users_namespaces", "un"}, "un.namespace_id = l.namespace_id"). Join("LEFT", []string{"users_projects", "ul"}, "ul.project_id = l.id"). - Join("LEFT", []string{"namespaces", "n"}, "n.id = l.namespace_id"). // Team stuff - Join("LEFT", []string{"team_namespaces", "tn"}, " l.namespace_id = tn.namespace_id"). - Join("LEFT", []string{"team_members", "tm"}, "tm.team_id = tn.team_id"). Join("LEFT", []string{"team_projects", "tl"}, "l.id = tl.project_id"). Join("LEFT", []string{"team_members", "tm2"}, "tm2.team_id = tl.team_id"). // The actual condition Where( builder.Or( builder.Or(builder.Eq{"ul.right": RightRead}), - builder.Or(builder.Eq{"un.right": RightRead}), builder.Or(builder.Eq{"tl.right": RightRead}), - builder.Or(builder.Eq{"tn.right": RightRead}), builder.Or(builder.Eq{"ul.right": RightWrite}), - builder.Or(builder.Eq{"un.right": RightWrite}), builder.Or(builder.Eq{"tl.right": RightWrite}), - builder.Or(builder.Eq{"tn.right": RightWrite}), builder.Or(builder.Eq{"ul.right": RightAdmin}), - builder.Or(builder.Eq{"un.right": RightAdmin}), builder.Or(builder.Eq{"tl.right": RightAdmin}), - builder.Or(builder.Eq{"tn.right": RightAdmin}), ), builder.Eq{"l.id": l.ID}, ). @@ -85,10 +69,7 @@ func ListUsersFromProject(s *xorm.Session, l *Project, search string) (users []* uidmap[l.OwnerID] = true for _, u := range userids { uidmap[u.ProjectUserID] = true - uidmap[u.NamespaceOwnerUserID] = true - uidmap[u.NamespaceUserID] = true uidmap[u.TeamProjectUserID] = true - uidmap[u.TeamNamespaceUserID] = true } uids := make([]int64, 0, len(uidmap)) diff --git a/pkg/modules/auth/openid/openid.go b/pkg/modules/auth/openid/openid.go index aa80890ce..dfa5522fc 100644 --- a/pkg/modules/auth/openid/openid.go +++ b/pkg/modules/auth/openid/openid.go @@ -244,7 +244,7 @@ func getOrCreateUser(s *xorm.Session, cl *claims, issuer, subject string) (u *us } } - // And create its namespace + // And create their project err = models.CreateNewProjectForUser(s, u) if err != nil { return nil, err diff --git a/pkg/routes/api/v1/user_register.go b/pkg/routes/api/v1/user_register.go index b6e6d40ea..1fcc77b48 100644 --- a/pkg/routes/api/v1/user_register.go +++ b/pkg/routes/api/v1/user_register.go @@ -62,7 +62,7 @@ func RegisterUser(c echo.Context) error { return handler.HandleHTTPError(err, c) } - // Add its namespace + // Create their initial project err = models.CreateNewProjectForUser(s, newUser) if err != nil { _ = s.Rollback() diff --git a/pkg/routes/metrics.go b/pkg/routes/metrics.go index ebe279436..2676f9dfa 100644 --- a/pkg/routes/metrics.go +++ b/pkg/routes/metrics.go @@ -51,10 +51,6 @@ func setupMetrics(a *echo.Group) { metrics.UserCountKey, user.User{}, }, - { - metrics.NamespaceCountKey, - models.Namespace{}, - }, { metrics.TaskCountKey, models.Task{},