Conversation
There was no way to overwrite all group members meaning just sending the actual value, instead one had to keep track of changes or remove all members to add the new ones again. Now a http PUT method allows to set the members array.
|
not quite ready to merge, just for review if I am doing it right |
|
|
||
| if err := json.NewDecoder(r.Body).Decode(&g); err != nil { | ||
| h.H.WriteError(w, r, errors.WithStack(err)) | ||
| if err := h.checkRequest(r, h.PrefixResource(GroupsResource), "create"); err != nil { |
There was a problem hiding this comment.
isn't it better to always first check the request?
There was a problem hiding this comment.
Yes, maybe I was using g here for some reason which was why it was decoded first, but as it stands now the order can be reversed´the way you did it.
| if err := h.Manager.RemoveGroupMembers(id, m.Members); err != nil { | ||
| w.WriteHeader(http.StatusNoContent) | ||
| } | ||
|
|
| return nil | ||
| } | ||
|
|
||
| func (m *SQLManager) applyInTransaction(requests ...func(tx *sqlx.Tx) error) error { |
There was a problem hiding this comment.
check if rollbacks are correct
|
shouldn't this function (and the next one) be non capital because it is not checking the request at all, it is just a helper right? |
I'm not sure right now, I think they need to be upper case for swagger docs to work. I'd have to check, otherwise all of the handlers can be lower case. |
| w.WriteHeader(http.StatusNoContent) | ||
| } | ||
|
|
||
| func (h *Handler) OverwriteGroupMembers(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { |
There was a problem hiding this comment.
I would probably rename it to "UpdateGroup"
There was a problem hiding this comment.
I think I'm going for UpdateGroupMembers because the http PUT url is GroupsHandlerPath + "/:id/members" so only one group is affected, not all of them
|
|
||
| if err := json.NewDecoder(r.Body).Decode(&g); err != nil { | ||
| h.H.WriteError(w, r, errors.WithStack(err)) | ||
| if err := h.checkRequest(r, h.PrefixResource(GroupsResource), "create"); err != nil { |
There was a problem hiding this comment.
Yes, maybe I was using g here for some reason which was why it was decoded first, but as it stands now the order can be reversed´the way you did it.
| return nil | ||
| } | ||
|
|
||
| func (m *SQLManager) applyInTransaction(requests ...func(tx *sqlx.Tx) error) error { |
There was a problem hiding this comment.
requests are really transactions, right?
There was a problem hiding this comment.
A transaction is a sequence of requests I would rather say.
|
|
||
| for _, req := range requests { | ||
| if err := req(tx); err != nil { | ||
| tx.Rollback() |
There was a problem hiding this comment.
If rollback fails, the error should be returned instead
if err := tx.Rollback(); err != nil {
return err
}
| } | ||
|
|
||
| func (m *SQLManager) OverwriteGroupMembers(group string, members []string) error { | ||
| if err := m.applyInTransaction(m.deleteGroup(group), m.createGroup(group), m.addGroupMembers(group, members)); err != nil { |
There was a problem hiding this comment.
this can be simplified to return m.ApplyIn...
| return func(tx *sqlx.Tx) error { | ||
| for _, subject := range subjects { | ||
| if _, err := tx.Exec(m.DB.Rebind("DELETE FROM hydra_warden_group_member WHERE member=? AND group_id=?"), subject, group); err != nil { | ||
| if err := tx.Rollback(); err != nil { |
There was a problem hiding this comment.
You have duplicate rollbacks here, let applyInTransaction handle rollbacks instead!
| return func(tx *sqlx.Tx) error { | ||
| for _, subject := range subjects { | ||
| if _, err := tx.Exec(m.DB.Rebind("INSERT INTO hydra_warden_group_member (group_id, member) VALUES (?, ?)"), group, subject); err != nil { | ||
| if err := tx.Rollback(); err != nil { |
There was a problem hiding this comment.
Rollback is already covered by applyInTransaction
| func (m *SQLManager) createGroup(group string) func(tx *sqlx.Tx) error { | ||
| return func(tx *sqlx.Tx) error { | ||
| if _, err := tx.Exec(m.DB.Rebind("INSERT INTO hydra_warden_group (id) VALUES (?)"), group); err != nil { | ||
| return err |
There was a problem hiding this comment.
Normal errors do not have stack traces in go, to add a stack trace do return errors.WithStack(err)
There was a problem hiding this comment.
Oh now I got it, I thought that errors.WithStack(err) just has to be called once to get the whole stacktrace.
There was a problem hiding this comment.
Exactly, and it also needs to be called at the location which is the deepest in the stack trace and there only once - otherwise you'll overwrite the stack trace. This is a bit tricky unfortunately. The rule is that we wrap all errors coming from other libraries but don't wrap errors coming from our own. That way we ensure that traces are always as deep as possible in the stack.
There was a problem hiding this comment.
So this should be actually without a stacktrace?
| func (m *SQLManager) deleteGroup(id string) func(tx *sqlx.Tx) error { | ||
| return func(tx *sqlx.Tx) error { | ||
| if _, err := tx.Exec(m.DB.Rebind("DELETE FROM hydra_warden_group WHERE id=?"), id); err != nil { | ||
| return err |
There was a problem hiding this comment.
Normal errors do not have stack traces in go, to add a stack trace do return errors.WithStack(err)
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err |
There was a problem hiding this comment.
Normal errors do not have stack traces in go, to add a stack trace do return errors.WithStack(err)
|
ready for review @arekkas |
aeneasr
left a comment
There was a problem hiding this comment.
Totally forgot about this one, have some questions. I'll check out the SQL implementation in more detail because the changes are a bit complex.
| // oauth2: hydra.warden.groups | ||
| // | ||
| // Responses: | ||
| // 204: emptyResponse |
There was a problem hiding this comment.
PUT requests typically don't return 204 responses but instead 200 + body. 204 is typically used for DELETE responses to aknowledge that the resource is gone
There was a problem hiding this comment.
I may not have changed everything correctly when copying the comments
There was a problem hiding this comment.
It's also in the response, see w.WriteHeader(http.StatusNoContent)
| return func(tx *sqlx.Tx) error { | ||
| _, err := tx.Exec(m.DB.Rebind("INSERT INTO hydra_warden_group (id) VALUES (?)"), group) | ||
|
|
||
| return errors.WithStack(err) |
There was a problem hiding this comment.
Not sure if this works for nil values? So if error is nil, does this return nil as well or not?
There was a problem hiding this comment.
https://godoc.org/github.com/pkg/errors#WithStack
I looked it up it works as expected
There was a problem hiding this comment.
Absolutely, it returns nil in that case: https://github.com/pkg/errors/blob/master/errors.go#L145
|
This is now tracked as ory/keto#10 |
* transfer UpdateRoleMembers from ory/hydra#768 to keto * fix tests by using right http method & correcting sql request * Change behavior to overwrite the whole role instead of just the members. + small sql migration fix
There was no way to overwrite all group members meaning just sending the actual value, instead one had to keep track of changes or remove all members to add the new ones again.
Now a http PUT method allows to set the members array.
closes #745