feat: more changes

This commit is contained in:
Jordan Knott
2020-12-08 19:44:48 -06:00
parent eff2044a6b
commit 33f06c1035
24 changed files with 1000 additions and 394 deletions

View File

@ -229,15 +229,16 @@ func (q *Queries) GetAllVisibleProjectsForUserID(ctx context.Context, userID uui
}
const getInvitedMembersForProjectID = `-- name: GetInvitedMembersForProjectID :many
SELECT email, invited_on FROM project_member_invited AS pmi
SELECT uai.user_account_invited_id, email, invited_on FROM project_member_invited AS pmi
INNER JOIN user_account_invited AS uai
ON uai.user_account_invited_id = pmi.user_account_invited_id
WHERE project_id = $1
`
type GetInvitedMembersForProjectIDRow struct {
Email string `json:"email"`
InvitedOn time.Time `json:"invited_on"`
UserAccountInvitedID uuid.UUID `json:"user_account_invited_id"`
Email string `json:"email"`
InvitedOn time.Time `json:"invited_on"`
}
func (q *Queries) GetInvitedMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]GetInvitedMembersForProjectIDRow, error) {
@ -249,7 +250,7 @@ func (q *Queries) GetInvitedMembersForProjectID(ctx context.Context, projectID u
var items []GetInvitedMembersForProjectIDRow
for rows.Next() {
var i GetInvitedMembersForProjectIDRow
if err := rows.Scan(&i.Email, &i.InvitedOn); err != nil {
if err := rows.Scan(&i.UserAccountInvitedID, &i.Email, &i.InvitedOn); err != nil {
return nil, err
}
items = append(items, i)

View File

@ -44,7 +44,7 @@ SELECT project_id, role_code FROM project_member WHERE user_id = $1;
SELECT project_id FROM project_member WHERE user_id = $1;
-- name: GetInvitedMembersForProjectID :many
SELECT email, invited_on FROM project_member_invited AS pmi
SELECT uai.user_account_invited_id, email, invited_on FROM project_member_invited AS pmi
INNER JOIN user_account_invited AS uai
ON uai.user_account_invited_id = pmi.user_account_invited_id
WHERE project_id = $1;

View File

@ -183,10 +183,9 @@ type ComplexityRoot struct {
}
MemberSearchResult struct {
Confirmed func(childComplexity int) int
Invited func(childComplexity int) int
Joined func(childComplexity int) int
ID func(childComplexity int) int
Similarity func(childComplexity int) int
Status func(childComplexity int) int
User func(childComplexity int) int
}
@ -1027,26 +1026,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.MemberList.Teams(childComplexity), true
case "MemberSearchResult.confirmed":
if e.complexity.MemberSearchResult.Confirmed == nil {
case "MemberSearchResult.id":
if e.complexity.MemberSearchResult.ID == nil {
break
}
return e.complexity.MemberSearchResult.Confirmed(childComplexity), true
case "MemberSearchResult.invited":
if e.complexity.MemberSearchResult.Invited == nil {
break
}
return e.complexity.MemberSearchResult.Invited(childComplexity), true
case "MemberSearchResult.joined":
if e.complexity.MemberSearchResult.Joined == nil {
break
}
return e.complexity.MemberSearchResult.Joined(childComplexity), true
return e.complexity.MemberSearchResult.ID(childComplexity), true
case "MemberSearchResult.similarity":
if e.complexity.MemberSearchResult.Similarity == nil {
@ -1055,6 +1040,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.MemberSearchResult.Similarity(childComplexity), true
case "MemberSearchResult.status":
if e.complexity.MemberSearchResult.Status == nil {
break
}
return e.complexity.MemberSearchResult.Status(childComplexity), true
case "MemberSearchResult.user":
if e.complexity.MemberSearchResult.User == nil {
break
@ -2841,6 +2833,11 @@ type TaskChecklist {
items: [TaskChecklistItem!]!
}
enum ShareStatus {
INVITED
JOINED
}
enum RoleLevel {
ADMIN
MEMBER
@ -3452,16 +3449,16 @@ type DeleteInvitedUserAccountPayload {
}
input MemberSearchFilter {
SearchFilter: String!
searchFilter: String!
projectID: UUID
}
type MemberSearchResult {
similarity: Int!
user: UserAccount!
confirmed: Boolean!
invited: Boolean!
joined: Boolean!
id: String!
user: UserAccount
status: ShareStatus!
}
type UpdateUserInfoPayload {
@ -6373,6 +6370,40 @@ func (ec *executionContext) _MemberSearchResult_similarity(ctx context.Context,
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) _MemberSearchResult_id(ctx context.Context, field graphql.CollectedField, obj *MemberSearchResult) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "MemberSearchResult",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) _MemberSearchResult_user(ctx context.Context, field graphql.CollectedField, obj *MemberSearchResult) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -6397,17 +6428,14 @@ func (ec *executionContext) _MemberSearchResult_user(ctx context.Context, field
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*db.UserAccount)
fc.Result = res
return ec.marshalNUserAccount2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋdbᚐUserAccount(ctx, field.Selections, res)
return ec.marshalOUserAccount2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋdbᚐUserAccount(ctx, field.Selections, res)
}
func (ec *executionContext) _MemberSearchResult_confirmed(ctx context.Context, field graphql.CollectedField, obj *MemberSearchResult) (ret graphql.Marshaler) {
func (ec *executionContext) _MemberSearchResult_status(ctx context.Context, field graphql.CollectedField, obj *MemberSearchResult) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
@ -6424,7 +6452,7 @@ func (ec *executionContext) _MemberSearchResult_confirmed(ctx context.Context, f
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Confirmed, nil
return obj.Status, nil
})
if err != nil {
ec.Error(ctx, err)
@ -6436,77 +6464,9 @@ func (ec *executionContext) _MemberSearchResult_confirmed(ctx context.Context, f
}
return graphql.Null
}
res := resTmp.(bool)
res := resTmp.(ShareStatus)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) _MemberSearchResult_invited(ctx context.Context, field graphql.CollectedField, obj *MemberSearchResult) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "MemberSearchResult",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Invited, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) _MemberSearchResult_joined(ctx context.Context, field graphql.CollectedField, obj *MemberSearchResult) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "MemberSearchResult",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Joined, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
return ec.marshalNShareStatus2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐShareStatus(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_createProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@ -16279,7 +16239,7 @@ func (ec *executionContext) unmarshalInputMemberSearchFilter(ctx context.Context
for k, v := range asMap {
switch k {
case "SearchFilter":
case "searchFilter":
var err error
it.SearchFilter, err = ec.unmarshalNString2string(ctx, v)
if err != nil {
@ -17982,23 +17942,15 @@ func (ec *executionContext) _MemberSearchResult(ctx context.Context, sel ast.Sel
if out.Values[i] == graphql.Null {
invalids++
}
case "id":
out.Values[i] = ec._MemberSearchResult_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "user":
out.Values[i] = ec._MemberSearchResult_user(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "confirmed":
out.Values[i] = ec._MemberSearchResult_confirmed(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "invited":
out.Values[i] = ec._MemberSearchResult_invited(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "joined":
out.Values[i] = ec._MemberSearchResult_joined(ctx, field, obj)
case "status":
out.Values[i] = ec._MemberSearchResult_status(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
@ -21486,6 +21438,15 @@ func (ec *executionContext) unmarshalNSetTaskComplete2githubᚗcomᚋjordanknott
return ec.unmarshalInputSetTaskComplete(ctx, v)
}
func (ec *executionContext) unmarshalNShareStatus2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐShareStatus(ctx context.Context, v interface{}) (ShareStatus, error) {
var res ShareStatus
return res, res.UnmarshalGQL(v)
}
func (ec *executionContext) marshalNShareStatus2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐShareStatus(ctx context.Context, sel ast.SelectionSet, v ShareStatus) graphql.Marshaler {
return v
}
func (ec *executionContext) unmarshalNSortTaskGroup2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐSortTaskGroup(ctx context.Context, v interface{}) (SortTaskGroup, error) {
return ec.unmarshalInputSortTaskGroup(ctx, v)
}
@ -22625,6 +22586,17 @@ func (ec *executionContext) unmarshalOUpdateProjectName2ᚖgithubᚗcomᚋjordan
return &res, err
}
func (ec *executionContext) marshalOUserAccount2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋdbᚐUserAccount(ctx context.Context, sel ast.SelectionSet, v db.UserAccount) graphql.Marshaler {
return ec._UserAccount(ctx, sel, &v)
}
func (ec *executionContext) marshalOUserAccount2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋdbᚐUserAccount(ctx context.Context, sel ast.SelectionSet, v *db.UserAccount) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec._UserAccount(ctx, sel, v)
}
func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler {
if v == nil {
return graphql.Null

View File

@ -249,16 +249,15 @@ type MemberList struct {
}
type MemberSearchFilter struct {
SearchFilter string `json:"SearchFilter"`
SearchFilter string `json:"searchFilter"`
ProjectID *uuid.UUID `json:"projectID"`
}
type MemberSearchResult struct {
Similarity int `json:"similarity"`
ID string `json:"id"`
User *db.UserAccount `json:"user"`
Confirmed bool `json:"confirmed"`
Invited bool `json:"invited"`
Joined bool `json:"joined"`
Status ShareStatus `json:"status"`
}
type NewProject struct {
@ -830,3 +829,44 @@ func (e *RoleLevel) UnmarshalGQL(v interface{}) error {
func (e RoleLevel) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
type ShareStatus string
const (
ShareStatusInvited ShareStatus = "INVITED"
ShareStatusJoined ShareStatus = "JOINED"
)
var AllShareStatus = []ShareStatus{
ShareStatusInvited,
ShareStatusJoined,
}
func (e ShareStatus) IsValid() bool {
switch e {
case ShareStatusInvited, ShareStatusJoined:
return true
}
return false
}
func (e ShareStatus) String() string {
return string(e)
}
func (e *ShareStatus) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = ShareStatus(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid ShareStatus", str)
}
return nil
}
func (e ShareStatus) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}

View File

@ -172,6 +172,11 @@ type TaskChecklist {
items: [TaskChecklistItem!]!
}
enum ShareStatus {
INVITED
JOINED
}
enum RoleLevel {
ADMIN
MEMBER
@ -783,16 +788,16 @@ type DeleteInvitedUserAccountPayload {
}
input MemberSearchFilter {
SearchFilter: String!
searchFilter: String!
projectID: UUID
}
type MemberSearchResult {
similarity: Int!
user: UserAccount!
confirmed: Boolean!
invited: Boolean!
joined: Boolean!
id: String!
user: UserAccount
status: ShareStatus!
}
type UpdateUserInfoPayload {

View File

@ -1310,31 +1310,52 @@ func (r *queryResolver) SearchMembers(ctx context.Context, input MemberSearchFil
return []MemberSearchResult{}, err
}
invitedMembers, err := r.Repository.GetInvitedMembersForProjectID(ctx, *input.ProjectID)
if err != nil {
logger.New(ctx).WithField("projectID", input.ProjectID).WithError(err).Error("error while getting member data")
return []MemberSearchResult{}, err
}
sortList := []string{}
masterList := map[string]uuid.UUID{}
masterList := map[string]MasterEntry{}
for _, member := range availableMembers {
sortList = append(sortList, member.Username)
sortList = append(sortList, member.Email)
masterList[member.Username] = member.UserID
masterList[member.Email] = member.UserID
masterList[member.Username] = MasterEntry{ID: member.UserID, MemberType: MemberTypeJoined}
masterList[member.Email] = MasterEntry{ID: member.UserID, MemberType: MemberTypeJoined}
}
logger.New(ctx).Info("fuzzy rank finder")
for _, member := range invitedMembers {
sortList = append(sortList, member.Email)
logger.New(ctx).WithField("Email", member.Email).Info("adding member")
masterList[member.Email] = MasterEntry{ID: member.UserAccountInvitedID, MemberType: MemberTypeInvited}
}
logger.New(ctx).WithField("searchFilter", input.SearchFilter).Info(sortList)
rankedList := fuzzy.RankFind(input.SearchFilter, sortList)
logger.New(ctx).Info(rankedList)
results := []MemberSearchResult{}
memberList := map[uuid.UUID]bool{}
for _, rank := range rankedList {
if _, ok := memberList[masterList[rank.Target]]; !ok {
logger.New(ctx).WithFields(log.Fields{"source": rank.Source, "target": rank.Target}).Info("searching")
userID := masterList[rank.Target]
user, err := r.Repository.GetUserAccountByID(ctx, userID)
if err != nil {
if err == sql.ErrNoRows {
continue
entry, _ := masterList[rank.Target]
_, ok := memberList[entry.ID]
logger.New(ctx).WithField("ok", ok).WithField("target", rank.Target).Info("checking rank")
if !ok {
if entry.MemberType == MemberTypeJoined {
logger.New(ctx).WithFields(log.Fields{"source": rank.Source, "target": rank.Target}).Info("searching")
entry := masterList[rank.Target]
user, err := r.Repository.GetUserAccountByID(ctx, entry.ID)
if err != nil {
if err == sql.ErrNoRows {
continue
}
return []MemberSearchResult{}, err
}
return []MemberSearchResult{}, err
results = append(results, MemberSearchResult{ID: user.UserID.String(), User: &user, Status: ShareStatusJoined, Similarity: rank.Distance})
} else {
logger.New(ctx).WithField("id", rank.Target).Info("adding target")
results = append(results, MemberSearchResult{ID: rank.Target, Status: ShareStatusInvited, Similarity: rank.Distance})
}
results = append(results, MemberSearchResult{User: &user, Joined: false, Confirmed: false, Similarity: rank.Distance})
memberList[masterList[rank.Target]] = true
memberList[entry.ID] = true
}
}
return results, nil
@ -1621,9 +1642,7 @@ func (r *Resolver) Task() TaskResolver { return &taskResolver{r} }
func (r *Resolver) TaskChecklist() TaskChecklistResolver { return &taskChecklistResolver{r} }
// TaskChecklistItem returns TaskChecklistItemResolver implementation.
func (r *Resolver) TaskChecklistItem() TaskChecklistItemResolver {
return &taskChecklistItemResolver{r}
}
func (r *Resolver) TaskChecklistItem() TaskChecklistItemResolver { return &taskChecklistItemResolver{r} }
// TaskGroup returns TaskGroupResolver implementation.
func (r *Resolver) TaskGroup() TaskGroupResolver { return &taskGroupResolver{r} }
@ -1652,3 +1671,21 @@ type taskGroupResolver struct{ *Resolver }
type taskLabelResolver struct{ *Resolver }
type teamResolver struct{ *Resolver }
type userAccountResolver struct{ *Resolver }
// !!! WARNING !!!
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
// one last chance to move it out of harms way if you want. There are two reasons this happens:
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
// it when you're done.
// - You have helper methods in this file. Move them out to keep these resolver files clean.
type MemberType string
const (
MemberTypeInvited MemberType = "INVITED"
MemberTypeJoined MemberType = "JOINED"
)
type MasterEntry struct {
MemberType MemberType
ID uuid.UUID
}

View File

@ -1,3 +1,8 @@
enum ShareStatus {
INVITED
JOINED
}
enum RoleLevel {
ADMIN
MEMBER

View File

@ -30,16 +30,16 @@ type DeleteInvitedUserAccountPayload {
}
input MemberSearchFilter {
SearchFilter: String!
searchFilter: String!
projectID: UUID
}
type MemberSearchResult {
similarity: Int!
user: UserAccount!
confirmed: Boolean!
invited: Boolean!
joined: Boolean!
id: String!
user: UserAccount
status: ShareStatus!
}
type UpdateUserInfoPayload {