Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web,server): Projects Recycle bin #1160

Closed
wants to merge 12 commits into from
133 changes: 133 additions & 0 deletions server/e2e/gql_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,136 @@ func TestSortByUpdatedAt(t *testing.T) {
edges.Element(1).Object().Value("node").Object().Value("name").Equal("project3-test")
edges.Element(2).Object().Value("node").Object().Value("name").Equal("project1-test")
}

// go test -v -run TestArchiveProject ./e2e/...

func TestArchiveProject(t *testing.T) {

e := StartServer(t, &config.Config{
Origins: []string{"https://example.com"},
AuthSrv: config.AuthSrvConfig{
Disabled: true,
},
}, true, baseSeeder)

createProject(e, "project1-test")
project2ID := createProject(e, "project2-test")
createProject(e, "project3-test")

// Archive 'project2'
requestBody := GraphQLRequest{
OperationName: "ArchiveProject",
Query: `mutation ArchiveProject($projectId: ID!, $archived: Boolean!) {
updateProject(input: {projectId: $projectId, archived: $archived}) {
project {
id
isArchived
__typename
}
__typename
}
}`,
Variables: map[string]any{
"projectId": project2ID,
"archived": true,
},
}
e.POST("/api/graphql").
WithHeader("Origin", "https://example.com").
WithHeader("X-Reearth-Debug-User", uID.String()).
WithHeader("Content-Type", "application/json").
WithJSON(requestBody).
Expect().
Status(http.StatusOK).
JSON()

requestBody = GraphQLRequest{
OperationName: "GetProjects",
Query: `query GetProjects($teamId: ID!, $includeArchived: Boolean, $pagination: Pagination, $keyword: String, $sort: ProjectSort) {
projects(teamId: $teamId, includeArchived: $includeArchived, pagination: $pagination, keyword: $keyword, sort: $sort) {
edges {
node {
id
...ProjectFragment
scene {
id
__typename
}
__typename
}
__typename
}
nodes {
id
...ProjectFragment
scene {
id
__typename
}
__typename
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
__typename
}
totalCount
__typename
}
}
fragment ProjectFragment on Project {
id
name
description
imageUrl
isArchived
isBasicAuthActive
basicAuthUsername
basicAuthPassword
publicTitle
publicDescription
publicImage
alias
enableGa
trackingId
publishmentStatus
updatedAt
createdAt
coreSupport
starred
__typename
}`,
Variables: map[string]any{
"teamId": wID.String(),
"includeArchived": false,
"pagination": map[string]any{
"first": 16,
},
"sort": map[string]string{
"field": "UPDATEDAT",
"direction": "DESC",
},
},
}
hexaforce marked this conversation as resolved.
Show resolved Hide resolved

edges := e.POST("/api/graphql").
WithHeader("Origin", "https://example.com").
WithHeader("X-Reearth-Debug-User", uID.String()).
WithHeader("Content-Type", "application/json").
WithJSON(requestBody).
Expect().
Status(http.StatusOK).
JSON().
Object().
Value("data").Object().
Value("projects").Object().
Value("edges").Array()

// `project2-test` is archived and will not be retrieved
edges.Length().Equal(3)
edges.Element(0).Object().Value("node").Object().Value("name").Equal("project3-test")
edges.Element(1).Object().Value("node").Object().Value("name").Equal("project1-test")
edges.Element(2).Object().Value("node").Object().Value("name").Equal("p1")
}
2 changes: 1 addition & 1 deletion server/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require (
github.com/kennygrant/sanitize v1.2.4
github.com/labstack/echo/v4 v4.11.4
github.com/mitchellh/mapstructure v1.5.0
github.com/oklog/ulid v1.3.1
github.com/paulmach/go.geojson v1.4.0
github.com/pkg/errors v0.9.1
github.com/ravilushqa/otelgqlgen v0.15.0
Expand Down Expand Up @@ -116,7 +117,6 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/nicksnyder/go-i18n/v2 v2.4.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/cors v1.10.1 // indirect
Expand Down
5 changes: 3 additions & 2 deletions server/gql/project.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Project implements Node {
enableGa: Boolean!
trackingId: String!
starred: Boolean!
isDeleted: Boolean!
}

type ProjectAliasAvailability {
Expand Down Expand Up @@ -140,13 +141,13 @@ type ProjectEdge {
extend type Query {
projects(
teamId: ID!
includeArchived: Boolean
pagination: Pagination
keyword: String
sort: ProjectSort
): ProjectConnection!
): ProjectConnection! # not included deleted projects
checkProjectAlias(alias: String!): ProjectAliasAvailability!
starredProjects(teamId: ID!): ProjectConnection!
deletedProjects(teamId: ID!): ProjectConnection!
}

extend type Mutation {
Expand Down
4 changes: 2 additions & 2 deletions server/internal/adapter/gql/loader_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ func (c *ProjectLoader) Fetch(ctx context.Context, ids []gqlmodel.ID) ([]*gqlmod
return projects, nil
}

func (c *ProjectLoader) FindByWorkspace(ctx context.Context, wsID gqlmodel.ID, keyword *string, sort *project.SortType, pagination *gqlmodel.Pagination) (*gqlmodel.ProjectConnection, error) {
func (c *ProjectLoader) FindByWorkspace(ctx context.Context, wsID gqlmodel.ID, includeArchived *bool, keyword *string, sort *project.SortType, pagination *gqlmodel.Pagination) (*gqlmodel.ProjectConnection, error) {
tid, err := gqlmodel.ToID[accountdomain.Workspace](wsID)
if err != nil {
return nil, err
}

res, pi, err := c.usecase.FindByWorkspace(ctx, tid, keyword, sort, gqlmodel.ToPagination(pagination), getOperator(ctx))
res, pi, err := c.usecase.FindByWorkspace(ctx, tid, includeArchived, keyword, sort, gqlmodel.ToPagination(pagination), getOperator(ctx))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion server/internal/adapter/gql/resolver_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func (r *queryResolver) Scene(ctx context.Context, projectID gqlmodel.ID) (*gqlm
}

func (r *queryResolver) Projects(ctx context.Context, teamID gqlmodel.ID, includeArchived *bool, pagination *gqlmodel.Pagination, keyword *string, sortType *gqlmodel.ProjectSort) (*gqlmodel.ProjectConnection, error) {
return loaders(ctx).Project.FindByWorkspace(ctx, teamID, keyword, gqlmodel.ProjectSortTypeFrom(sortType), pagination)
return loaders(ctx).Project.FindByWorkspace(ctx, teamID, includeArchived, keyword, gqlmodel.ProjectSortTypeFrom(sortType), pagination)
}

func (r *queryResolver) DatasetSchemas(ctx context.Context, sceneID gqlmodel.ID, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.DatasetSchemaConnection, error) {
Expand Down
2 changes: 1 addition & 1 deletion server/internal/adapter/gql/resolver_team.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (r *teamResolver) Assets(ctx context.Context, obj *gqlmodel.Team, first *in
}

func (r *teamResolver) Projects(ctx context.Context, obj *gqlmodel.Team, includeArchived *bool, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.ProjectConnection, error) {
return loaders(ctx).Project.FindByWorkspace(ctx, obj.ID, nil, nil, &gqlmodel.Pagination{
return loaders(ctx).Project.FindByWorkspace(ctx, obj.ID, includeArchived, nil, nil, &gqlmodel.Pagination{
First: first,
Last: last,
After: after,
Expand Down
3 changes: 3 additions & 0 deletions server/internal/infrastructure/memory/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ func (r *Project) FindByWorkspace(ctx context.Context, id accountdomain.Workspac
result := []*project.Project{}
for _, d := range r.data {
if d.Workspace() == id && (filter.Keyword == nil || strings.Contains(d.Name(), *filter.Keyword)) {
if filter.IncludeArchived != nil && !*filter.IncludeArchived && d.IsArchived() {
continue
}
result = append(result, d)
}
}
Expand Down
1 change: 1 addition & 0 deletions server/internal/infrastructure/mongo/mongodoc/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ProjectDocument struct {
TrackingID string
// Scene string
Starred bool
Deleted bool
}

type ProjectConsumer = Consumer[*ProjectDocument, *project.Project]
Expand Down
19 changes: 19 additions & 0 deletions server/internal/infrastructure/mongo/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ func (r *Project) FindByWorkspace(ctx context.Context, id accountdomain.Workspac
})
}

if uFilter.IncludeArchived != nil {
if !*uFilter.IncludeArchived {
filter = mongox.And(filter, "deleted", false)
}
}

return r.paginate(ctx, filter, uFilter.Sort, uFilter.Pagination)
}

Expand All @@ -109,6 +115,19 @@ func (r *Project) FindStarredByWorkspace(ctx context.Context, id accountdomain.W
return r.find(ctx, filter)
}

func (r *Project) FindDeletedByWorkspace(ctx context.Context, id accountdomain.WorkspaceID) ([]*project.Project, error) {
if !r.f.CanRead(id) {
return nil, repo.ErrOperationDenied
}

filter := bson.M{
"team": id.String(),
"deleted": true,
}

return r.find(ctx, filter)
}

func (r *Project) FindByPublicName(ctx context.Context, name string) (*project.Project, error) {
if name == "" {
return nil, rerror.ErrNotFound
Expand Down
9 changes: 5 additions & 4 deletions server/internal/usecase/interactor/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ func (i *Project) Fetch(ctx context.Context, ids []id.ProjectID, _ *usecase.Oper
return i.projectRepo.FindByIDs(ctx, ids)
}

func (i *Project) FindByWorkspace(ctx context.Context, id accountdomain.WorkspaceID, keyword *string, sort *project.SortType, p *usecasex.Pagination, operator *usecase.Operator) ([]*project.Project, *usecasex.PageInfo, error) {
func (i *Project) FindByWorkspace(ctx context.Context, id accountdomain.WorkspaceID, includeArchived *bool, keyword *string, sort *project.SortType, p *usecasex.Pagination, operator *usecase.Operator) ([]*project.Project, *usecasex.PageInfo, error) {
return i.projectRepo.FindByWorkspace(ctx, id, repo.ProjectFilter{
Pagination: p,
Sort: sort,
Keyword: keyword,
IncludeArchived: includeArchived,
Pagination: p,
Sort: sort,
Keyword: keyword,
})
}

Expand Down
2 changes: 1 addition & 1 deletion server/internal/usecase/interfaces/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ var (

type Project interface {
Fetch(context.Context, []id.ProjectID, *usecase.Operator) ([]*project.Project, error)
FindByWorkspace(context.Context, accountdomain.WorkspaceID, *string, *project.SortType, *usecasex.Pagination, *usecase.Operator) ([]*project.Project, *usecasex.PageInfo, error)
FindByWorkspace(context.Context, accountdomain.WorkspaceID, *bool, *string, *project.SortType, *usecasex.Pagination, *usecase.Operator) ([]*project.Project, *usecasex.PageInfo, error)
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
FindStarredByWorkspace(context.Context, accountdomain.WorkspaceID, *usecase.Operator) ([]*project.Project, error)
Create(context.Context, CreateProjectParam, *usecase.Operator) (*project.Project, error)
Update(context.Context, UpdateProjectParam, *usecase.Operator) (*project.Project, error)
Expand Down
7 changes: 4 additions & 3 deletions server/internal/usecase/repo/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
)

type ProjectFilter struct {
Sort *project.SortType
Keyword *string
Pagination *usecasex.Pagination
IncludeArchived *bool
Sort *project.SortType
Keyword *string
Pagination *usecasex.Pagination
}

type Project interface {
Expand Down
Loading
Loading