auth

Paddy 2015-07-15 Parent:cf1aef6eb81f

178:0a2c3d677161 Go to Latest

auth/client_postgres.go

Update to use a generic event emitter. Rather can creating a purpose-built event emitter for each and every event we need to emit (I'm looking at you, login verification event) which is _downright silly_, we're now using a generic event publisher that's based on saying "HEY A MODEL UPDATED". This means we need to change all our setup code in authd to use events.NewNSQPublisher or events.NewStdoutPublisher instead of our homegrown solutions. Which also means updating our config to take an events.Publisher instead of our LoginVerificationNotifier (blergh). Our Context also now uses an events.Publisher instead of a LoginVerificationNotifier. Party all around! We also replaced our SendLoginVerification helper method on Context with a SendModelEvent helper method on Context, which is just a light wrapper around events.PublishModelEvent. Of course, all this means we need to update our email_verification listener to listen to the correct channel (based on the model we want updates about) and filter down to a Created action or our new custom action for "the customer wants their verification resent", which I'm OK making a special case and not generic, because c'mon. But we had a subtle change to all our constants, some of which are unofficial constants now. I'm unsure how I feel about this. We also updated our email_verification listener so that we're unmarshalling to a custom loginEvent, which is just an events.Event that overwrites the Data property to be an auth.Login instance. This is to make sure we don't need to wrangle a map[string]interface{}, which is no fun. I'm also OK with special-casing like this, because it's 1) a tiny amount of code, 2) properly utilising composition, and 3) the only way I can think of to cleanly accomplish what I want. I also added a note about GetLogin's deficient handling of logins, namely that it doesn't recognise admins and return Verification codes to them, which would be a useful property for internal tools to take advantage of. Ah well. I updated the Profile and Login implementations so they're now event.Model instances, mainly by just exporting some strings from them through getters that will let us automatically build an Event from them. This lets us use the PublishModelEvent helper. I updated our CreateProfileHandler to properly mangle the login Verification property, and to fire off the ActionCreated events for the new Login and the new Profile. I updated our GetLoginHandler and UpdateLoginHandler to properly mangle the loginVerification property. God that's annoying. :-/ You'll note I didn't start publishing the events.ActionUpdated or events.ActionDeleted events for Profiles or Logins yet, and didn't bother publishing any events for literally any other type. That's because I'm a lazy piece of crap and will end up publishing them when I absolutely have to. Part of that is because if a channel isn't created/being read for a topic, the messages will just stack up in NSQ, and I don't want that. But mostly I'm lazy. Finally, I got to delete the entire profile_verification.go file, because we're no longer special-casing that. Hooray!

History
paddy@151 1 package auth
paddy@151 2
paddy@151 3 import (
paddy@151 4 "code.secondbit.org/uuid.hg"
paddy@151 5 "github.com/lib/pq"
paddy@151 6 "github.com/secondbit/pan"
paddy@151 7 )
paddy@151 8
paddy@151 9 func (c Client) GetSQLTableName() string {
paddy@151 10 return "clients"
paddy@151 11 }
paddy@151 12
paddy@151 13 func (e Endpoint) GetSQLTableName() string {
paddy@151 14 return "endpoints"
paddy@151 15 }
paddy@151 16
paddy@151 17 func (p *postgres) getClientSQL(id uuid.ID) *pan.Query {
paddy@151 18 var client Client
paddy@151 19 fields, _ := pan.GetFields(client)
paddy@151 20 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(client))
paddy@151 21 query.IncludeWhere()
paddy@151 22 query.Include(pan.GetUnquotedColumn(client, "ID")+" = ? AND "+pan.GetUnquotedColumn(client, "Deleted")+" = ?", id, false)
paddy@151 23 return query.FlushExpressions(" ")
paddy@151 24 }
paddy@151 25
paddy@151 26 func (p *postgres) getClient(id uuid.ID) (Client, error) {
paddy@151 27 query := p.getClientSQL(id)
paddy@151 28 rows, err := p.db.Query(query.String(), query.Args...)
paddy@151 29 if err != nil {
paddy@151 30 return Client{}, err
paddy@151 31 }
paddy@151 32 var client Client
paddy@151 33 var found bool
paddy@151 34 for rows.Next() {
paddy@151 35 err := pan.Unmarshal(rows, &client)
paddy@151 36 if err != nil {
paddy@151 37 return client, err
paddy@151 38 }
paddy@151 39 found = true
paddy@151 40 }
paddy@151 41 if err = rows.Err(); err != nil {
paddy@151 42 return client, err
paddy@151 43 }
paddy@151 44 if !found {
paddy@151 45 return client, ErrClientNotFound
paddy@151 46 }
paddy@151 47 return client, nil
paddy@151 48 }
paddy@151 49
paddy@151 50 func (p *postgres) saveClientSQL(client Client) *pan.Query {
paddy@151 51 fields, values := pan.GetFields(client)
paddy@151 52 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(client))
paddy@151 53 query.Include("(" + pan.QueryList(fields) + ")")
paddy@151 54 query.Include("VALUES")
paddy@151 55 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@151 56 return query.FlushExpressions(" ")
paddy@151 57 }
paddy@151 58
paddy@151 59 func (p *postgres) saveClient(client Client) error {
paddy@151 60 query := p.saveClientSQL(client)
paddy@151 61 _, err := p.db.Exec(query.String(), query.Args...)
paddy@151 62 if e, ok := err.(*pq.Error); ok && e.Constraint == "clients_pkey" {
paddy@151 63 err = ErrClientAlreadyExists
paddy@151 64 }
paddy@151 65 return err
paddy@151 66 }
paddy@151 67
paddy@151 68 func (p *postgres) updateClientSQL(id uuid.ID, change ClientChange) *pan.Query {
paddy@151 69 var client Client
paddy@151 70 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(client)+" SET ")
paddy@151 71 query.IncludeIfNotNil(pan.GetUnquotedColumn(client, "Secret")+" = ?", change.Secret)
paddy@151 72 query.IncludeIfNotNil(pan.GetUnquotedColumn(client, "OwnerID")+" = ?", change.OwnerID)
paddy@151 73 query.IncludeIfNotNil(pan.GetUnquotedColumn(client, "Name")+" = ?", change.Name)
paddy@151 74 query.IncludeIfNotNil(pan.GetUnquotedColumn(client, "Logo")+" = ?", change.Logo)
paddy@151 75 query.IncludeIfNotNil(pan.GetUnquotedColumn(client, "Website")+" = ?", change.Website)
paddy@151 76 query.IncludeIfNotNil(pan.GetUnquotedColumn(client, "Deleted")+" = ?", change.Deleted)
paddy@151 77 query.FlushExpressions(", ")
paddy@151 78 query.IncludeWhere()
paddy@151 79 query.Include(pan.GetUnquotedColumn(client, "ID")+" = ?", id)
paddy@151 80 return query.FlushExpressions(" ")
paddy@151 81 }
paddy@151 82
paddy@151 83 func (p *postgres) updateClient(id uuid.ID, change ClientChange) error {
paddy@151 84 if change.Empty() {
paddy@151 85 return nil
paddy@151 86 }
paddy@151 87 query := p.updateClientSQL(id, change)
paddy@151 88 _, err := p.db.Exec(query.String(), query.Args...)
paddy@151 89 return err
paddy@151 90 }
paddy@151 91
paddy@151 92 func (p *postgres) listClientsByOwnerSQL(ownerID uuid.ID, num, offset int) *pan.Query {
paddy@151 93 var client Client
paddy@151 94 fields, _ := pan.GetFields(client)
paddy@151 95 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(client))
paddy@151 96 query.IncludeWhere()
paddy@151 97 query.Include(pan.GetUnquotedColumn(client, "OwnerID")+" = ? AND "+pan.GetUnquotedColumn(client, "Deleted")+" = ?", ownerID, false)
paddy@164 98 if num > 0 {
paddy@164 99 query.IncludeLimit(int64(num))
paddy@164 100 }
paddy@151 101 query.IncludeOffset(int64(offset))
paddy@151 102 return query.FlushExpressions(" ")
paddy@151 103 }
paddy@151 104
paddy@151 105 func (p *postgres) listClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error) {
paddy@151 106 query := p.listClientsByOwnerSQL(ownerID, num, offset)
paddy@151 107 rows, err := p.db.Query(query.String(), query.Args...)
paddy@151 108 if err != nil {
paddy@151 109 return []Client{}, err
paddy@151 110 }
paddy@151 111 var clients []Client
paddy@151 112 for rows.Next() {
paddy@151 113 var client Client
paddy@151 114 err = pan.Unmarshal(rows, &client)
paddy@151 115 if err != nil {
paddy@151 116 return clients, err
paddy@151 117 }
paddy@151 118 clients = append(clients, client)
paddy@151 119 }
paddy@151 120 if err = rows.Err(); err != nil {
paddy@151 121 return clients, err
paddy@151 122 }
paddy@151 123 return clients, nil
paddy@151 124 }
paddy@151 125
paddy@164 126 func (p *postgres) deleteClientsByOwnerSQL(ownerID uuid.ID) *pan.Query {
paddy@164 127 var client Client
paddy@164 128 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(client)+" SET")
paddy@164 129 query.Include(pan.GetUnquotedColumn(client, "Deleted")+"= ?", true)
paddy@164 130 query.IncludeWhere()
paddy@164 131 query.Include(pan.GetUnquotedColumn(client, "OwnerID")+" = ?", ownerID)
paddy@164 132 return query.FlushExpressions(" ")
paddy@164 133 }
paddy@164 134
paddy@164 135 func (p *postgres) deleteClientsByOwner(ownerID uuid.ID) error {
paddy@164 136 query := p.deleteClientsByOwnerSQL(ownerID)
paddy@164 137 _, err := p.db.Exec(query.String(), query.Args...)
paddy@164 138 return err
paddy@164 139 }
paddy@164 140
paddy@151 141 func (p *postgres) addEndpointsSQL(endpoints []Endpoint) *pan.Query {
paddy@151 142 fields, _ := pan.GetFields(endpoints[0])
paddy@151 143 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(endpoints[0]))
paddy@151 144 query.Include("(" + pan.QueryList(fields) + ")")
paddy@151 145 query.Include("VALUES")
paddy@151 146 query.FlushExpressions(" ")
paddy@151 147 for _, endpoint := range endpoints {
paddy@151 148 _, values := pan.GetFields(endpoint)
paddy@151 149 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@151 150 }
paddy@151 151 return query.FlushExpressions(", ")
paddy@151 152 }
paddy@151 153
paddy@151 154 func (p *postgres) addEndpoints(endpoints []Endpoint) error {
paddy@151 155 if len(endpoints) < 1 {
paddy@151 156 return nil
paddy@151 157 }
paddy@151 158 query := p.addEndpointsSQL(endpoints)
paddy@151 159 _, err := p.db.Exec(query.String(), query.Args...)
paddy@151 160 if e, ok := err.(*pq.Error); ok && e.Constraint == "endpoints_pkey" {
paddy@151 161 return ErrEndpointAlreadyExists
paddy@151 162 }
paddy@151 163 return err
paddy@151 164 }
paddy@151 165
paddy@151 166 func (p *postgres) removeEndpointSQL(client, endpoint uuid.ID) *pan.Query {
paddy@151 167 var e Endpoint
paddy@151 168 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(e))
paddy@151 169 query.IncludeWhere()
paddy@151 170 query.Include(pan.GetUnquotedColumn(e, "ID")+" = ? AND "+pan.GetUnquotedColumn(e, "ClientID")+" = ?", endpoint, client)
paddy@151 171 return query.FlushExpressions(" ")
paddy@151 172 }
paddy@151 173
paddy@151 174 func (p *postgres) removeEndpoint(client, endpoint uuid.ID) error {
paddy@151 175 query := p.removeEndpointSQL(client, endpoint)
paddy@151 176 res, err := p.db.Exec(query.String(), query.Args...)
paddy@151 177 if err != nil {
paddy@151 178 return err
paddy@151 179 }
paddy@151 180 rows, err := res.RowsAffected()
paddy@151 181 if err != nil {
paddy@151 182 return err
paddy@151 183 }
paddy@151 184 if rows == 0 {
paddy@151 185 return ErrEndpointNotFound
paddy@151 186 }
paddy@151 187 return nil
paddy@151 188 }
paddy@151 189
paddy@164 190 func (p *postgres) removeEndpointsByClientIDSQL(client uuid.ID) *pan.Query {
paddy@164 191 var e Endpoint
paddy@164 192 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(e))
paddy@164 193 query.IncludeWhere()
paddy@164 194 query.Include(pan.GetUnquotedColumn(e, "ClientID")+" = ?", client)
paddy@164 195 return query.FlushExpressions(" ")
paddy@164 196 }
paddy@164 197
paddy@164 198 func (p *postgres) removeEndpointsByClientID(client uuid.ID) error {
paddy@164 199 query := p.removeEndpointsByClientIDSQL(client)
paddy@164 200 res, err := p.db.Exec(query.String(), query.Args...)
paddy@164 201 if err != nil {
paddy@164 202 return err
paddy@164 203 }
paddy@164 204 rows, err := res.RowsAffected()
paddy@164 205 if err != nil {
paddy@164 206 return err
paddy@164 207 }
paddy@164 208 if rows == 0 {
paddy@164 209 return ErrClientNotFound
paddy@164 210 }
paddy@164 211 return nil
paddy@164 212 }
paddy@164 213
paddy@151 214 func (p *postgres) getEndpointSQL(client, endpoint uuid.ID) *pan.Query {
paddy@151 215 var e Endpoint
paddy@151 216 fields, _ := pan.GetFields(e)
paddy@151 217 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(e))
paddy@151 218 query.IncludeWhere()
paddy@151 219 query.FlushExpressions(" ")
paddy@151 220 query.Include(pan.GetUnquotedColumn(e, "ID")+" = ?", endpoint)
paddy@151 221 query.Include(pan.GetUnquotedColumn(e, "ClientID")+" = ?", client)
paddy@151 222 return query.FlushExpressions(" AND ")
paddy@151 223 }
paddy@151 224
paddy@151 225 func (p *postgres) getEndpoint(client, endpoint uuid.ID) (Endpoint, error) {
paddy@151 226 query := p.getEndpointSQL(client, endpoint)
paddy@151 227 rows, err := p.db.Query(query.String(), query.Args...)
paddy@151 228 if err != nil {
paddy@151 229 return Endpoint{}, err
paddy@151 230 }
paddy@151 231 var e Endpoint
paddy@151 232 var found bool
paddy@151 233 for rows.Next() {
paddy@151 234 err := pan.Unmarshal(rows, &e)
paddy@151 235 if err != nil {
paddy@151 236 return e, err
paddy@151 237 }
paddy@151 238 found = true
paddy@151 239 }
paddy@151 240 if err = rows.Err(); err != nil {
paddy@151 241 return e, err
paddy@151 242 }
paddy@151 243 if !found {
paddy@151 244 return e, ErrEndpointNotFound
paddy@151 245 }
paddy@151 246 return e, nil
paddy@151 247 }
paddy@151 248
paddy@151 249 func (p *postgres) checkEndpointSQL(client uuid.ID, endpoint string) *pan.Query {
paddy@151 250 var e Endpoint
paddy@151 251 fields, _ := pan.GetFields(e)
paddy@151 252 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(e))
paddy@151 253 query.IncludeWhere()
paddy@151 254 query.FlushExpressions(" ")
paddy@151 255 query.Include(pan.GetUnquotedColumn(e, "ClientID")+" = ?", client)
paddy@151 256 query.Include(pan.GetUnquotedColumn(e, "NormalizedURI")+" = ?", endpoint)
paddy@151 257 return query.FlushExpressions(" AND ")
paddy@151 258 }
paddy@151 259
paddy@151 260 func (p *postgres) checkEndpoint(client uuid.ID, endpoint string) (bool, error) {
paddy@151 261 query := p.checkEndpointSQL(client, endpoint)
paddy@151 262 rows, err := p.db.Query(query.String(), query.Args...)
paddy@151 263 if err != nil {
paddy@151 264 return false, err
paddy@151 265 }
paddy@151 266 var found bool
paddy@151 267 for rows.Next() {
paddy@151 268 found = true
paddy@151 269 }
paddy@151 270 if err = rows.Err(); err != nil {
paddy@151 271 return found, err
paddy@151 272 }
paddy@151 273 return found, nil
paddy@151 274 }
paddy@151 275
paddy@151 276 func (p *postgres) listEndpointsSQL(client uuid.ID, num, offset int) *pan.Query {
paddy@151 277 var endpoint Endpoint
paddy@151 278 fields, _ := pan.GetFields(endpoint)
paddy@151 279 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(endpoint))
paddy@151 280 query.IncludeWhere()
paddy@151 281 query.Include(pan.GetUnquotedColumn(endpoint, "ClientID")+" = ?", client)
paddy@151 282 query.IncludeLimit(int64(num))
paddy@151 283 query.IncludeOffset(int64(offset))
paddy@151 284 return query.FlushExpressions(" ")
paddy@151 285 }
paddy@151 286
paddy@151 287 func (p *postgres) listEndpoints(client uuid.ID, num, offset int) ([]Endpoint, error) {
paddy@151 288 query := p.listEndpointsSQL(client, num, offset)
paddy@151 289 rows, err := p.db.Query(query.String(), query.Args...)
paddy@151 290 if err != nil {
paddy@151 291 return []Endpoint{}, err
paddy@151 292 }
paddy@151 293 var endpoints []Endpoint
paddy@151 294 for rows.Next() {
paddy@151 295 var endpoint Endpoint
paddy@151 296 err = pan.Unmarshal(rows, &endpoint)
paddy@151 297 if err != nil {
paddy@151 298 return endpoints, err
paddy@151 299 }
paddy@151 300 endpoints = append(endpoints, endpoint)
paddy@151 301 }
paddy@151 302 if err = rows.Err(); err != nil {
paddy@151 303 return endpoints, err
paddy@151 304 }
paddy@151 305 return endpoints, nil
paddy@151 306 }
paddy@151 307
paddy@151 308 func (p *postgres) countEndpointsSQL(client uuid.ID) *pan.Query {
paddy@151 309 var endpoint Endpoint
paddy@151 310 query := pan.New(pan.POSTGRES, "SELECT COUNT(*) FROM "+pan.GetTableName(endpoint))
paddy@151 311 query.IncludeWhere()
paddy@151 312 query.Include(pan.GetUnquotedColumn(endpoint, "ClientID")+" = ?", client)
paddy@151 313 return query.FlushExpressions(" ")
paddy@151 314 }
paddy@151 315
paddy@151 316 func (p *postgres) countEndpoints(client uuid.ID) (int64, error) {
paddy@151 317 query := p.countEndpointsSQL(client)
paddy@151 318 rows, err := p.db.Query(query.String(), query.Args...)
paddy@151 319 if err != nil {
paddy@151 320 return 0, err
paddy@151 321 }
paddy@151 322 var results int64
paddy@151 323 for rows.Next() {
paddy@151 324 err = pan.Unmarshal(rows, &results)
paddy@151 325 if err != nil {
paddy@151 326 return results, err
paddy@151 327 }
paddy@151 328 }
paddy@151 329 if err = rows.Err(); err != nil {
paddy@151 330 return results, err
paddy@151 331 }
paddy@151 332 return results, nil
paddy@151 333 }