backend for xcvr appview

simplify profiles, TODO make the oauth client profile update work

+31 -116
+13 -59
server/internal/db/lexicon.go
··· 3 3 import ( 4 4 "context" 5 5 "errors" 6 - "fmt" 7 6 "rvcx/internal/types" 8 - "strings" 9 7 ) 10 8 11 9 func (s *Store) InitializeProfile(did string, ··· 31 29 return nil 32 30 } 33 31 34 - type ProfileUpdate struct { 35 - DID string 36 - Name *string 37 - UpdateName bool 38 - Nick *string 39 - UpdateNick bool 40 - Status *string 41 - UpdateStatus bool 42 - Avatar *string 43 - UpdateAvatar bool 44 - Mime *string 45 - UpdateMime bool 46 - Color *uint64 47 - UpdateColor bool 48 - } 49 - 50 - func (s *Store) UpdateProfile(to *ProfileUpdate, ctx context.Context) error { 51 - setParts := []string{} 52 - args := []any{to.DID} 53 - idx := 2 54 - if to.UpdateName { 55 - setParts = append(setParts, fmt.Sprintf("display_name = $%d", idx)) 56 - args = append(args, to.Name) 57 - idx += 1 58 - } 59 - if to.UpdateNick { 60 - setParts = append(setParts, fmt.Sprintf("default_nick = $%d", idx)) 61 - args = append(args, to.Nick) 62 - idx += 1 63 - } 64 - if to.UpdateStatus { 65 - setParts = append(setParts, fmt.Sprintf("status = $%d", idx)) 66 - args = append(args, to.Status) 67 - idx += 1 68 - } 69 - if to.UpdateAvatar { 70 - setParts = append(setParts, fmt.Sprintf("avatar_cid = $%d", idx)) 71 - args = append(args, to.Avatar) 72 - idx += 1 73 - } 74 - if to.UpdateMime { 75 - setParts = append(setParts, fmt.Sprintf("avatar_mime = $%d", idx)) 76 - args = append(args, to.Mime) 77 - idx += 1 78 - } 79 - if to.UpdateColor { 80 - setParts = append(setParts, fmt.Sprintf("color = $%d", idx)) 81 - args = append(args, to.Color) 82 - idx += 1 83 - } 84 - if idx == 2 { 85 - return nil 86 - } 87 - sql := fmt.Sprintf("UPDATE profiles SET %s WHERE did = $1", 88 - strings.Join(setParts, ", ")) 89 - _, err := s.pool.Exec(ctx, sql, args...) 32 + func (s *Store) UpdateProfile(did string, displayname *string, defaultnick *string, status *string, color *uint64, ctx context.Context) error { 33 + _, err := s.pool.Exec(ctx, ` 34 + INSERT INTO profiles ( 35 + did, 36 + display_name, 37 + default_nick, 38 + status, 39 + color 40 + ) VALUES ( 41 + $1, $2, $3, $4, $5 42 + ) 43 + `, did, displayname, defaultnick, status, color) 90 44 if err != nil { 91 - return errors.New("error updating profile: " + err.Error()) 45 + return errors.New("i'm not sure what happened: " + err.Error()) 92 46 } 93 47 return nil 94 48 }
+16 -55
server/internal/recordmanager/profile.go
··· 4 4 "context" 5 5 "errors" 6 6 "rvcx/internal/atputils" 7 - "rvcx/internal/db" 8 7 "rvcx/internal/lex" 9 8 "rvcx/internal/oauth" 10 9 "rvcx/internal/types" ··· 13 12 ) 14 13 15 14 func (rm *RecordManager) AcceptProfile(p lex.ProfileRecord, did string, ctx context.Context) error { 16 - pu := convertToPu(p, did) 17 - err := rm.storeProfile(pu, ctx) 15 + err := rm.storeProfile(did, &p, ctx) 18 16 if err != nil { 19 17 return errors.New("failed to store profile: " + err.Error()) 20 18 } ··· 25 23 return rm.db.DeleteProfile(did, cid, ctx) 26 24 } 27 25 28 - func convertToPu(p lex.ProfileRecord, did string) *db.ProfileUpdate { 29 - var avatar *string 30 - var mime *string 31 - if p.Avatar != nil { 32 - ava := p.Avatar.Ref.String() 33 - avatar = &ava 34 - mime = &p.Avatar.MimeType 35 - } 36 - return &db.ProfileUpdate{ 37 - DID: did, 38 - Name: p.DisplayName, 39 - UpdateName: true, 40 - Nick: p.DefaultNick, 41 - UpdateNick: true, 42 - Status: p.Status, 43 - UpdateStatus: true, 44 - Color: p.Color, 45 - UpdateColor: true, 46 - Avatar: avatar, 47 - UpdateAvatar: true, 48 - Mime: mime, 49 - UpdateMime: true, 50 - } 51 - } 52 - 53 26 func (rm *RecordManager) CreateInitialProfile(sessData *atoauth.ClientSessionData, ctx context.Context) error { 54 27 nick := "wanderer" 55 28 status := "just setting up my xcvr" ··· 73 46 } 74 47 75 48 func (rm *RecordManager) PostProfile(cs *atoauth.ClientSession, ctx context.Context, p *types.PostProfileRequest) error { 76 - pu, err := rm.validateProfile(cs.Data.AccountDID.String(), p) 49 + err := rm.validateProfile(p) 77 50 if err != nil { 78 51 return errors.New("couldn't validate profile: " + err.Error()) 79 52 } 80 - err = rm.updateProfile(cs, p.DisplayName, p.DefaultNick, p.Status, p.Color, ctx) 53 + pr, err := rm.updateProfile(cs, p.DisplayName, p.DefaultNick, p.Status, p.Color, ctx) 81 54 if err != nil { 82 55 return errors.New("couldn't create profile: " + err.Error()) 83 56 } 84 - err = rm.storeProfile(pu, ctx) 57 + err = rm.storeProfile(cs.Data.AccountDID.String(), pr, ctx) 85 58 if err != nil { 86 59 return errors.New("couldn't store profile: " + err.Error()) 87 60 } 88 61 return nil 89 62 } 90 63 91 - func (rm *RecordManager) storeProfile(pu *db.ProfileUpdate, ctx context.Context) error { 92 - err := rm.db.UpdateProfile(pu, ctx) 64 + func (rm *RecordManager) storeProfile(did string, p *lex.ProfileRecord, ctx context.Context) error { 65 + err := rm.db.UpdateProfile(did, p.DisplayName, p.DefaultNick, p.Status, p.Color, ctx) 93 66 if err != nil { 94 67 return errors.New("error updating profile: " + err.Error()) 95 68 } 96 69 return nil 97 70 } 98 71 99 - func (rm *RecordManager) updateProfile(cs *atoauth.ClientSession, name *string, nick *string, status *string, color *uint64, ctx context.Context) error { 72 + func (rm *RecordManager) updateProfile(cs *atoauth.ClientSession, name *string, nick *string, status *string, color *uint64, ctx context.Context) (*lex.ProfileRecord, error) { 100 73 profilerecord := &lex.ProfileRecord{ 101 74 DisplayName: name, 102 75 DefaultNick: nick, 103 76 Status: status, 104 77 Color: color, 105 78 } 106 - _, err := oauth.UpdateXCVRProfile(cs, profilerecord, ctx) 79 + pr, err := oauth.UpdateXCVRProfile(cs, profilerecord, ctx) 107 80 if err != nil { 108 - return err 81 + return nil, err 109 82 } 110 - return nil 83 + return pr, nil 111 84 } 112 85 113 86 func (rm *RecordManager) createProfile(name *string, nick *string, status *string, color *uint64, sessData *atoauth.ClientSessionData, ctx context.Context) (*lex.ProfileRecord, error) { ··· 128 101 return p, nil 129 102 } 130 103 131 - func (rm *RecordManager) validateProfile(did string, p *types.PostProfileRequest) (*db.ProfileUpdate, error) { 132 - var pu db.ProfileUpdate 133 - pu.DID = did 104 + func (rm *RecordManager) validateProfile(p *types.PostProfileRequest) error { 134 105 if p.DisplayName != nil { 135 106 if atputils.ValidateGraphemesAndLength(*p.DisplayName, 64, 640) { 136 - return nil, errors.New("displayname too long") 107 + return errors.New("displayname too long") 137 108 } 138 - pu.Name = p.DisplayName 139 - pu.UpdateName = true 140 109 } 141 110 if p.DefaultNick != nil { 142 111 if atputils.ValidateLength(*p.DefaultNick, 16) { 143 - return nil, errors.New("nick too long") 112 + return errors.New("nick too long") 144 113 } 145 - pu.Nick = p.DefaultNick 146 - pu.UpdateNick = true 147 114 } 148 115 if p.Status != nil { 149 116 if atputils.ValidateGraphemesAndLength(*p.Status, 640, 6400) { 150 - return nil, errors.New("status too long") 117 + return errors.New("status too long") 151 118 } 152 - pu.Status = p.Status 153 - pu.UpdateStatus = true 154 119 } 155 120 if p.Avatar != nil { 156 121 // TODO think about how to do avatars! 157 - pu.Avatar = p.Avatar 158 - pu.UpdateAvatar = true 159 122 } 160 123 if p.Color != nil { 161 124 if *p.Color > 16777215 || *p.Color < 0 { 162 - return nil, errors.New("color out of bounds") 125 + return errors.New("color out of bounds") 163 126 } 164 - pu.Color = p.Color 165 - pu.UpdateColor = true 166 127 } 167 - return &pu, nil 128 + return nil 168 129 }
+2 -2
server/internal/types/lexicons.go
··· 10 10 11 11 type Profile struct { 12 12 DID string 13 - DisplayName string 14 - DefaultNick string 13 + DisplayName *string 14 + DefaultNick *string 15 15 Status *string 16 16 AvatarCID *string 17 17 AvatarMIME *string