feat: so many stuffs

This commit is contained in:
Jordan Knott
2020-11-22 14:11:13 -06:00
parent 451581e934
commit eff2044a6b
50 changed files with 3144 additions and 28 deletions

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,23 @@ type CreateTeamMemberPayload struct {
TeamMember *Member `json:"teamMember"`
}
type DeleteInvitedProjectMember struct {
ProjectID uuid.UUID `json:"projectID"`
Email string `json:"email"`
}
type DeleteInvitedProjectMemberPayload struct {
InvitedMember *InvitedMember `json:"invitedMember"`
}
type DeleteInvitedUserAccount struct {
InvitedUserID uuid.UUID `json:"invitedUserID"`
}
type DeleteInvitedUserAccountPayload struct {
InvitedUser *InvitedUserAccount `json:"invitedUser"`
}
type DeleteProject struct {
ProjectID uuid.UUID `json:"projectID"`
}
@ -183,9 +200,22 @@ type InviteProjectMembers struct {
}
type InviteProjectMembersPayload struct {
Ok bool `json:"ok"`
ProjectID uuid.UUID `json:"projectID"`
Members []Member `json:"members"`
Ok bool `json:"ok"`
ProjectID uuid.UUID `json:"projectID"`
Members []Member `json:"members"`
InvitedMembers []InvitedMember `json:"invitedMembers"`
}
type InvitedMember struct {
Email string `json:"email"`
InvitedOn time.Time `json:"invitedOn"`
}
type InvitedUserAccount struct {
ID uuid.UUID `json:"id"`
Email string `json:"email"`
InvitedOn time.Time `json:"invitedOn"`
Member *MemberList `json:"member"`
}
type LogoutUser struct {

View File

@ -86,6 +86,13 @@ type UserAccount {
member: MemberList!
}
type InvitedUserAccount {
id: ID!
email: String!
invitedOn: Time!
member: MemberList!
}
type Team {
id: ID!
createdAt: Time!
@ -93,6 +100,12 @@ type Team {
members: [Member!]!
}
type InvitedMember {
email: String!
invitedOn: Time!
}
type Project {
id: ID!
createdAt: Time!
@ -100,6 +113,7 @@ type Project {
team: Team
taskGroups: [TaskGroup!]!
members: [Member!]!
invitedMembers: [InvitedMember!]!
labels: [ProjectLabel!]!
}
@ -184,6 +198,7 @@ directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!)
type Query {
organizations: [Organization!]!
users: [UserAccount!]!
invitedUsers: [InvitedUserAccount!]!
findUser(input: FindUser!): UserAccount!
findProject(input: FindProject!):
Project! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
@ -344,6 +359,18 @@ extend type Mutation {
DeleteProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
updateProjectMemberRole(input: UpdateProjectMemberRole!):
UpdateProjectMemberRolePayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
deleteInvitedProjectMember(input: DeleteInvitedProjectMember!):
DeleteInvitedProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
}
input DeleteInvitedProjectMember {
projectID: UUID!
email: String!
}
type DeleteInvitedProjectMemberPayload {
invitedMember: InvitedMember!
}
input MemberInvite {
@ -360,6 +387,7 @@ type InviteProjectMembersPayload {
ok: Boolean!
projectID: UUID!
members: [Member!]!
invitedMembers: [InvitedMember!]!
}
input DeleteProjectMember {
@ -729,6 +757,8 @@ extend type Mutation {
UserAccount! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
deleteUserAccount(input: DeleteUserAccount!):
DeleteUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
deleteInvitedUserAccount(input: DeleteInvitedUserAccount!):
DeleteInvitedUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
logoutUser(input: LogoutUser!): Boolean!
clearProfileAvatar: UserAccount!
@ -744,6 +774,14 @@ extend type Query {
searchMembers(input: MemberSearchFilter!): [MemberSearchResult!]!
}
input DeleteInvitedUserAccount {
invitedUserID: UUID!
}
type DeleteInvitedUserAccountPayload {
invitedUser: InvitedUserAccount!
}
input MemberSearchFilter {
SearchFilter: String!
projectID: UUID
@ -813,3 +851,4 @@ type DeleteUserAccountPayload {
ok: Boolean!
userAccount: UserAccount!
}

View File

@ -127,6 +127,7 @@ func (r *mutationResolver) UpdateProjectLabelColor(ctx context.Context, input Up
func (r *mutationResolver) InviteProjectMembers(ctx context.Context, input InviteProjectMembers) (*InviteProjectMembersPayload, error) {
members := []Member{}
invitedMembers := []InvitedMember{}
for _, invitedMember := range input.Members {
if invitedMember.Email != nil && invitedMember.UserID != nil {
return &InviteProjectMembersPayload{Ok: false}, &gqlerror.Error{
@ -144,6 +145,7 @@ func (r *mutationResolver) InviteProjectMembers(ctx context.Context, input Invit
}
}
if invitedMember.UserID != nil {
// Invite by user ID
addedAt := time.Now().UTC()
_, err := r.Repository.CreateProjectMember(ctx, db.CreateProjectMemberParams{ProjectID: input.ProjectID, UserID: *invitedMember.UserID, AddedAt: addedAt, RoleCode: "member"})
if err != nil {
@ -171,9 +173,39 @@ func (r *mutationResolver) InviteProjectMembers(ctx context.Context, input Invit
ProfileIcon: profileIcon,
Role: &db.Role{Code: role.Code, Name: role.Name},
})
} else {
// Invite by email
// if invited user does not exist, create entry
invitedUser, err := r.Repository.GetInvitedUserByEmail(ctx, *invitedMember.Email)
now := time.Now().UTC()
if err != nil {
if err == sql.ErrNoRows {
invitedUser, err = r.Repository.CreateInvitedUser(ctx, *invitedMember.Email)
if err != nil {
return &InviteProjectMembersPayload{Ok: false}, err
}
} else {
return &InviteProjectMembersPayload{Ok: false}, err
}
}
_, err = r.Repository.CreateInvitedProjectMember(ctx, db.CreateInvitedProjectMemberParams{
ProjectID: input.ProjectID,
UserAccountInvitedID: invitedUser.UserAccountInvitedID,
})
if err != nil {
return &InviteProjectMembersPayload{Ok: false}, err
}
logger.New(ctx).Info("adding invited member")
invitedMembers = append(invitedMembers, InvitedMember{Email: *invitedMember.Email, InvitedOn: now})
// send out invitation
// add project invite entry
// send out notification?
}
}
return &InviteProjectMembersPayload{Ok: false, ProjectID: input.ProjectID, Members: members}, nil
return &InviteProjectMembersPayload{Ok: false, ProjectID: input.ProjectID, Members: members, InvitedMembers: invitedMembers}, nil
}
func (r *mutationResolver) DeleteProjectMember(ctx context.Context, input DeleteProjectMember) (*DeleteProjectMemberPayload, error) {
@ -233,6 +265,20 @@ func (r *mutationResolver) UpdateProjectMemberRole(ctx context.Context, input Up
return &UpdateProjectMemberRolePayload{Ok: true, Member: &member}, err
}
func (r *mutationResolver) DeleteInvitedProjectMember(ctx context.Context, input DeleteInvitedProjectMember) (*DeleteInvitedProjectMemberPayload, error) {
member, err := r.Repository.GetProjectMemberInvitedIDByEmail(ctx, input.Email)
if err != nil {
return &DeleteInvitedProjectMemberPayload{}, err
}
err = r.Repository.DeleteInvitedProjectMemberByID(ctx, member.ProjectMemberInvitedID)
if err != nil {
return &DeleteInvitedProjectMemberPayload{}, err
}
return &DeleteInvitedProjectMemberPayload{
InvitedMember: &InvitedMember{Email: member.Email, InvitedOn: member.InvitedOn},
}, nil
}
func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*db.Task, error) {
createdAt := time.Now().UTC()
logger.New(ctx).WithFields(log.Fields{"positon": input.Position, "taskGroupID": input.TaskGroupID}).Info("creating task")
@ -809,6 +855,20 @@ func (r *mutationResolver) DeleteUserAccount(ctx context.Context, input DeleteUs
return &DeleteUserAccountPayload{UserAccount: &user, Ok: true}, nil
}
func (r *mutationResolver) DeleteInvitedUserAccount(ctx context.Context, input DeleteInvitedUserAccount) (*DeleteInvitedUserAccountPayload, error) {
user, err := r.Repository.DeleteInvitedUserAccount(ctx, input.InvitedUserID)
if err != nil {
return &DeleteInvitedUserAccountPayload{}, err
}
return &DeleteInvitedUserAccountPayload{
InvitedUser: &InvitedUserAccount{
Email: user.Email,
ID: user.UserAccountInvitedID,
InvitedOn: user.InvitedOn,
},
}, err
}
func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) {
err := r.Repository.DeleteRefreshTokenByUserID(ctx, input.UserID)
return true, err
@ -979,6 +1039,18 @@ func (r *projectResolver) Members(ctx context.Context, obj *db.Project) ([]Membe
return members, nil
}
func (r *projectResolver) InvitedMembers(ctx context.Context, obj *db.Project) ([]InvitedMember, error) {
members, err := r.Repository.GetInvitedMembersForProjectID(ctx, obj.ProjectID)
if err != nil && err == sql.ErrNoRows {
return []InvitedMember{}, nil
}
invited := []InvitedMember{}
for _, member := range members {
invited = append(invited, InvitedMember{Email: member.Email, InvitedOn: member.InvitedOn})
}
return invited, err
}
func (r *projectResolver) Labels(ctx context.Context, obj *db.Project) ([]db.ProjectLabel, error) {
labels, err := r.Repository.GetProjectLabelsForProject(ctx, obj.ProjectID)
return labels, err
@ -1012,6 +1084,25 @@ func (r *queryResolver) Users(ctx context.Context) ([]db.UserAccount, error) {
return r.Repository.GetAllUserAccounts(ctx)
}
func (r *queryResolver) InvitedUsers(ctx context.Context) ([]InvitedUserAccount, error) {
invitedMembers, err := r.Repository.GetInvitedUserAccounts(ctx)
if err != nil {
if err == sql.ErrNoRows {
return []InvitedUserAccount{}, nil
}
return []InvitedUserAccount{}, err
}
members := []InvitedUserAccount{}
for _, invitedMember := range invitedMembers {
members = append(members, InvitedUserAccount{
ID: invitedMember.UserAccountInvitedID,
Email: invitedMember.Email,
InvitedOn: invitedMember.InvitedOn,
})
}
return members, nil
}
func (r *queryResolver) FindUser(ctx context.Context, input FindUser) (*db.UserAccount, error) {
account, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
if err == sql.ErrNoRows {

View File

@ -86,6 +86,13 @@ type UserAccount {
member: MemberList!
}
type InvitedUserAccount {
id: ID!
email: String!
invitedOn: Time!
member: MemberList!
}
type Team {
id: ID!
createdAt: Time!
@ -93,6 +100,12 @@ type Team {
members: [Member!]!
}
type InvitedMember {
email: String!
invitedOn: Time!
}
type Project {
id: ID!
createdAt: Time!
@ -100,6 +113,7 @@ type Project {
team: Team
taskGroups: [TaskGroup!]!
members: [Member!]!
invitedMembers: [InvitedMember!]!
labels: [ProjectLabel!]!
}

View File

@ -24,6 +24,7 @@ directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!)
type Query {
organizations: [Organization!]!
users: [UserAccount!]!
invitedUsers: [InvitedUserAccount!]!
findUser(input: FindUser!): UserAccount!
findProject(input: FindProject!):
Project! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)

View File

@ -5,6 +5,18 @@ extend type Mutation {
DeleteProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
updateProjectMemberRole(input: UpdateProjectMemberRole!):
UpdateProjectMemberRolePayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
deleteInvitedProjectMember(input: DeleteInvitedProjectMember!):
DeleteInvitedProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
}
input DeleteInvitedProjectMember {
projectID: UUID!
email: String!
}
type DeleteInvitedProjectMemberPayload {
invitedMember: InvitedMember!
}
input MemberInvite {
@ -21,6 +33,7 @@ type InviteProjectMembersPayload {
ok: Boolean!
projectID: UUID!
members: [Member!]!
invitedMembers: [InvitedMember!]!
}
input DeleteProjectMember {

View File

@ -4,6 +4,8 @@ extend type Mutation {
UserAccount! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
deleteUserAccount(input: DeleteUserAccount!):
DeleteUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
deleteInvitedUserAccount(input: DeleteInvitedUserAccount!):
DeleteInvitedUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
logoutUser(input: LogoutUser!): Boolean!
clearProfileAvatar: UserAccount!
@ -19,6 +21,14 @@ extend type Query {
searchMembers(input: MemberSearchFilter!): [MemberSearchResult!]!
}
input DeleteInvitedUserAccount {
invitedUserID: UUID!
}
type DeleteInvitedUserAccountPayload {
invitedUser: InvitedUserAccount!
}
input MemberSearchFilter {
SearchFilter: String!
projectID: UUID