diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..2cf63f46 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,11 @@ +{ + "permissions": { + "allow": [ + "Bash(just nix::develop default bash -c 'just codegen::proto >/dev/null && just codegen::db-schema >/dev/null && echo CODEGEN-OK && just check::test -c backend 2>&1 | tail -40 && just check::lint -c backend 2>&1 | tail -30')", + "Bash(just nix::develop default bash -c 'just check::lint -c backend 2>&1')", + "Bash(just nix::develop default bash -c 'just check::lint -c backend 2>&1 | grep -E \"\\\\.go:[0-9]+|successful|not successful\" ; just check::test -c backend 2>&1 | grep -E \"Ran [0-9]+|Passed|FAIL\"')", + "Bash(nix run *)", + "Bash(git add *)" + ] + } +} diff --git a/api/proto/API.md b/api/proto/API.md index 88d10f1c..63d5e429 100644 --- a/api/proto/API.md +++ b/api/proto/API.md @@ -483,6 +483,12 @@ - [user/messages/user_svc/add_role_response.proto](#user_messages_user_svc_add_role_response-proto) - [AddRoleResponse](#user-messages-user_svc-AddRoleResponse) +- [user/messages/user_svc/edit_profile_request.proto](#user_messages_user_svc_edit_profile_request-proto) + - [EditProfileRequest](#user-messages-user_svc-EditProfileRequest) + +- [user/messages/user_svc/edit_profile_response.proto](#user_messages_user_svc_edit_profile_response-proto) + - [EditProfileResponse](#user-messages-user_svc-EditProfileResponse) + - [user/messages/user_svc/get_request.proto](#user_messages_user_svc_get_request-proto) - [GetRequest](#user-messages-user_svc-GetRequest) @@ -789,6 +795,9 @@ See components/backend/internal/middleware/rbac.go. | email | [string](#string) | | | | roles | [GlobalRole](#user-entities-GlobalRole) | repeated | Populated from casbin on fetch; not persisted in ent DB. | | modified_at | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | | +| github_url | [string](#string) | | Profile links the user maintains via EditProfile; empty when unset. | +| renku_url | [string](#string) | | | +| linkedin_url | [string](#string) | | | @@ -5746,6 +5755,72 @@ casbin role for this hackathon; `is_waiting` is false once approved. + +
+ +## user/messages/user_svc/edit_profile_request.proto + + + + + +### EditProfileRequest +Edits the caller's own profile. There is no user id: the target is always +the user the token belongs to. An absent field is left as is; an empty +string clears the link. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| github_url | [string](#string) | optional | | +| renku_url | [string](#string) | optional | | +| linkedin_url | [string](#string) | optional | | + + + + + + + + + + + + + + + + + + +## user/messages/user_svc/edit_profile_response.proto + + + + + +### EditProfileResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| user | [user.entities.User](#user-entities-User) | | | + + + + + + + + + + + + + + + @@ -6068,6 +6143,7 @@ casbin role for this hackathon; `is_waiting` is false once approved. | Register | [messages.user_svc.RegisterRequest](#user-messages-user_svc-RegisterRequest) | [messages.user_svc.RegisterResponse](#user-messages-user_svc-RegisterResponse) | | | AddRole | [messages.user_svc.AddRoleRequest](#user-messages-user_svc-AddRoleRequest) | [messages.user_svc.AddRoleResponse](#user-messages-user_svc-AddRoleResponse) | | | RemoveRole | [messages.user_svc.RemoveRoleRequest](#user-messages-user_svc-RemoveRoleRequest) | [messages.user_svc.RemoveRoleResponse](#user-messages-user_svc-RemoveRoleResponse) | | +| EditProfile | [messages.user_svc.EditProfileRequest](#user-messages-user_svc-EditProfileRequest) | [messages.user_svc.EditProfileResponse](#user-messages-user_svc-EditProfileResponse) | | diff --git a/api/proto/user/entities/user.proto b/api/proto/user/entities/user.proto index bfd08072..824b765c 100644 --- a/api/proto/user/entities/user.proto +++ b/api/proto/user/entities/user.proto @@ -17,4 +17,8 @@ message User { // Populated from casbin on fetch; not persisted in ent DB. repeated GlobalRole roles = 7; google.protobuf.Timestamp modified_at = 8; + // Profile links the user maintains via EditProfile; empty when unset. + string github_url = 9; + string renku_url = 10; + string linkedin_url = 11; } diff --git a/api/proto/user/messages/user_svc/edit_profile_request.proto b/api/proto/user/messages/user_svc/edit_profile_request.proto new file mode 100644 index 00000000..0c1c9bae --- /dev/null +++ b/api/proto/user/messages/user_svc/edit_profile_request.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package user.messages.user_svc; + +option go_package = "github.com/swissdatasciencecenter/hackagon/components/backend/internal/proto/user/messages/user_svc"; + +// Edits the caller's own profile. There is no user id: the target is always +// the user the token belongs to. An absent field is left as is; an empty +// string clears the link. +message EditProfileRequest { + optional string github_url = 1; + optional string renku_url = 2; + optional string linkedin_url = 3; +} diff --git a/api/proto/user/messages/user_svc/edit_profile_response.proto b/api/proto/user/messages/user_svc/edit_profile_response.proto new file mode 100644 index 00000000..39275b99 --- /dev/null +++ b/api/proto/user/messages/user_svc/edit_profile_response.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package user.messages.user_svc; + +import "user/entities/user.proto"; + +option go_package = "github.com/swissdatasciencecenter/hackagon/components/backend/internal/proto/user/messages/user_svc"; + +message EditProfileResponse { + user.entities.User user = 1; +} diff --git a/api/proto/user/user_service.proto b/api/proto/user/user_service.proto index de4e204c..207cec20 100644 --- a/api/proto/user/user_service.proto +++ b/api/proto/user/user_service.proto @@ -4,6 +4,8 @@ package user; import "user/messages/user_svc/add_role_request.proto"; import "user/messages/user_svc/add_role_response.proto"; +import "user/messages/user_svc/edit_profile_request.proto"; +import "user/messages/user_svc/edit_profile_response.proto"; import "user/messages/user_svc/get_request.proto"; import "user/messages/user_svc/get_response.proto"; import "user/messages/user_svc/list_request.proto"; @@ -24,4 +26,5 @@ service UserService { rpc Register(user.messages.user_svc.RegisterRequest) returns (user.messages.user_svc.RegisterResponse); rpc AddRole(user.messages.user_svc.AddRoleRequest) returns (user.messages.user_svc.AddRoleResponse); rpc RemoveRole(user.messages.user_svc.RemoveRoleRequest) returns (user.messages.user_svc.RemoveRoleResponse); + rpc EditProfile(user.messages.user_svc.EditProfileRequest) returns (user.messages.user_svc.EditProfileResponse); } diff --git a/components/backend/Schema.md b/components/backend/Schema.md index adc2f85d..c24317e8 100644 --- a/components/backend/Schema.md +++ b/components/backend/Schema.md @@ -394,6 +394,9 @@ An authenticated user, synced from Keycloak on first login. | `keycloak_id` | string | yes | yes | no | no | Unique identifier from Keycloak (sub claim). | | `display_name` | string | no | no | no | yes | Preferred display name of the user. | | `email` | string | no | no | no | yes | Email of the user, same as in Keycloak | +| `github_url` | string | no | no | no | yes | Link to the user's GitHub profile, set by the user. | +| `renku_url` | string | no | no | no | yes | Link to the user's Renku profile, set by the user. | +| `linkedin_url` | string | no | no | no | yes | Link to the user's LinkedIn profile, set by the user. | | `created_at` | time.Time | yes | no | yes | yes | Timestamp when the user was first seen. | | `modified_at` | time.Time | yes | no | no | yes | Timestamp of the last profile update. | diff --git a/components/backend/db/schema/user.go b/components/backend/db/schema/user.go index 80ced4ff..476ed268 100644 --- a/components/backend/db/schema/user.go +++ b/components/backend/db/schema/user.go @@ -32,6 +32,14 @@ func (User) Fields() []ent.Field { Comment("Preferred display name of the user."), field.String("email").Optional().Default(""). Comment("Email of the user, same as in Keycloak"), + // The profile links below are owned by the platform, not Keycloak: the + // user edits them here, and the claim sync on login never touches them. + field.String("github_url").Optional().Default(""). + Comment("Link to the user's GitHub profile, set by the user."), + field.String("renku_url").Optional().Default(""). + Comment("Link to the user's Renku profile, set by the user."), + field.String("linkedin_url").Optional().Default(""). + Comment("Link to the user's LinkedIn profile, set by the user."), field.Time("created_at").Immutable().Default(time.Now). Comment("Timestamp when the user was first seen."), field.Time("modified_at"). diff --git a/components/backend/ent/migrate/schema.go b/components/backend/ent/migrate/schema.go index 09d1dbb4..a70b3dd8 100644 --- a/components/backend/ent/migrate/schema.go +++ b/components/backend/ent/migrate/schema.go @@ -635,6 +635,9 @@ var ( {Name: "keycloak_id", Type: field.TypeString, Unique: true}, {Name: "display_name", Type: field.TypeString, Nullable: true, Default: ""}, {Name: "email", Type: field.TypeString, Nullable: true, Default: ""}, + {Name: "github_url", Type: field.TypeString, Nullable: true, Default: ""}, + {Name: "renku_url", Type: field.TypeString, Nullable: true, Default: ""}, + {Name: "linkedin_url", Type: field.TypeString, Nullable: true, Default: ""}, {Name: "created_at", Type: field.TypeTime}, {Name: "modified_at", Type: field.TypeTime}, } diff --git a/components/backend/ent/mutation.go b/components/backend/ent/mutation.go index 6acf257e..26c9c576 100644 --- a/components/backend/ent/mutation.go +++ b/components/backend/ent/mutation.go @@ -12483,6 +12483,9 @@ type UserMutation struct { keycloak_id *string display_name *string email *string + github_url *string + renku_url *string + linkedin_url *string created_at *time.Time modified_at *time.Time clearedFields map[string]struct{} @@ -12843,6 +12846,153 @@ func (m *UserMutation) ResetEmail() { delete(m.clearedFields, user.FieldEmail) } +// SetGithubURL sets the "github_url" field. +func (m *UserMutation) SetGithubURL(s string) { + m.github_url = &s +} + +// GithubURL returns the value of the "github_url" field in the mutation. +func (m *UserMutation) GithubURL() (r string, exists bool) { + v := m.github_url + if v == nil { + return + } + return *v, true +} + +// OldGithubURL returns the old "github_url" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldGithubURL(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldGithubURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldGithubURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldGithubURL: %w", err) + } + return oldValue.GithubURL, nil +} + +// ClearGithubURL clears the value of the "github_url" field. +func (m *UserMutation) ClearGithubURL() { + m.github_url = nil + m.clearedFields[user.FieldGithubURL] = struct{}{} +} + +// GithubURLCleared returns if the "github_url" field was cleared in this mutation. +func (m *UserMutation) GithubURLCleared() bool { + _, ok := m.clearedFields[user.FieldGithubURL] + return ok +} + +// ResetGithubURL resets all changes to the "github_url" field. +func (m *UserMutation) ResetGithubURL() { + m.github_url = nil + delete(m.clearedFields, user.FieldGithubURL) +} + +// SetRenkuURL sets the "renku_url" field. +func (m *UserMutation) SetRenkuURL(s string) { + m.renku_url = &s +} + +// RenkuURL returns the value of the "renku_url" field in the mutation. +func (m *UserMutation) RenkuURL() (r string, exists bool) { + v := m.renku_url + if v == nil { + return + } + return *v, true +} + +// OldRenkuURL returns the old "renku_url" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldRenkuURL(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRenkuURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRenkuURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRenkuURL: %w", err) + } + return oldValue.RenkuURL, nil +} + +// ClearRenkuURL clears the value of the "renku_url" field. +func (m *UserMutation) ClearRenkuURL() { + m.renku_url = nil + m.clearedFields[user.FieldRenkuURL] = struct{}{} +} + +// RenkuURLCleared returns if the "renku_url" field was cleared in this mutation. +func (m *UserMutation) RenkuURLCleared() bool { + _, ok := m.clearedFields[user.FieldRenkuURL] + return ok +} + +// ResetRenkuURL resets all changes to the "renku_url" field. +func (m *UserMutation) ResetRenkuURL() { + m.renku_url = nil + delete(m.clearedFields, user.FieldRenkuURL) +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (m *UserMutation) SetLinkedinURL(s string) { + m.linkedin_url = &s +} + +// LinkedinURL returns the value of the "linkedin_url" field in the mutation. +func (m *UserMutation) LinkedinURL() (r string, exists bool) { + v := m.linkedin_url + if v == nil { + return + } + return *v, true +} + +// OldLinkedinURL returns the old "linkedin_url" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldLinkedinURL(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldLinkedinURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldLinkedinURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldLinkedinURL: %w", err) + } + return oldValue.LinkedinURL, nil +} + +// ClearLinkedinURL clears the value of the "linkedin_url" field. +func (m *UserMutation) ClearLinkedinURL() { + m.linkedin_url = nil + m.clearedFields[user.FieldLinkedinURL] = struct{}{} +} + +// LinkedinURLCleared returns if the "linkedin_url" field was cleared in this mutation. +func (m *UserMutation) LinkedinURLCleared() bool { + _, ok := m.clearedFields[user.FieldLinkedinURL] + return ok +} + +// ResetLinkedinURL resets all changes to the "linkedin_url" field. +func (m *UserMutation) ResetLinkedinURL() { + m.linkedin_url = nil + delete(m.clearedFields, user.FieldLinkedinURL) +} + // SetCreatedAt sets the "created_at" field. func (m *UserMutation) SetCreatedAt(t time.Time) { m.created_at = &t @@ -14353,7 +14503,7 @@ func (m *UserMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *UserMutation) Fields() []string { - fields := make([]string, 0, 6) + fields := make([]string, 0, 9) if m.username != nil { fields = append(fields, user.FieldUsername) } @@ -14366,6 +14516,15 @@ func (m *UserMutation) Fields() []string { if m.email != nil { fields = append(fields, user.FieldEmail) } + if m.github_url != nil { + fields = append(fields, user.FieldGithubURL) + } + if m.renku_url != nil { + fields = append(fields, user.FieldRenkuURL) + } + if m.linkedin_url != nil { + fields = append(fields, user.FieldLinkedinURL) + } if m.created_at != nil { fields = append(fields, user.FieldCreatedAt) } @@ -14388,6 +14547,12 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { return m.DisplayName() case user.FieldEmail: return m.Email() + case user.FieldGithubURL: + return m.GithubURL() + case user.FieldRenkuURL: + return m.RenkuURL() + case user.FieldLinkedinURL: + return m.LinkedinURL() case user.FieldCreatedAt: return m.CreatedAt() case user.FieldModifiedAt: @@ -14409,6 +14574,12 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldDisplayName(ctx) case user.FieldEmail: return m.OldEmail(ctx) + case user.FieldGithubURL: + return m.OldGithubURL(ctx) + case user.FieldRenkuURL: + return m.OldRenkuURL(ctx) + case user.FieldLinkedinURL: + return m.OldLinkedinURL(ctx) case user.FieldCreatedAt: return m.OldCreatedAt(ctx) case user.FieldModifiedAt: @@ -14450,6 +14621,27 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetEmail(v) return nil + case user.FieldGithubURL: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetGithubURL(v) + return nil + case user.FieldRenkuURL: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRenkuURL(v) + return nil + case user.FieldLinkedinURL: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetLinkedinURL(v) + return nil case user.FieldCreatedAt: v, ok := value.(time.Time) if !ok { @@ -14500,6 +14692,15 @@ func (m *UserMutation) ClearedFields() []string { if m.FieldCleared(user.FieldEmail) { fields = append(fields, user.FieldEmail) } + if m.FieldCleared(user.FieldGithubURL) { + fields = append(fields, user.FieldGithubURL) + } + if m.FieldCleared(user.FieldRenkuURL) { + fields = append(fields, user.FieldRenkuURL) + } + if m.FieldCleared(user.FieldLinkedinURL) { + fields = append(fields, user.FieldLinkedinURL) + } return fields } @@ -14520,6 +14721,15 @@ func (m *UserMutation) ClearField(name string) error { case user.FieldEmail: m.ClearEmail() return nil + case user.FieldGithubURL: + m.ClearGithubURL() + return nil + case user.FieldRenkuURL: + m.ClearRenkuURL() + return nil + case user.FieldLinkedinURL: + m.ClearLinkedinURL() + return nil } return fmt.Errorf("unknown User nullable field %s", name) } @@ -14540,6 +14750,15 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldEmail: m.ResetEmail() return nil + case user.FieldGithubURL: + m.ResetGithubURL() + return nil + case user.FieldRenkuURL: + m.ResetRenkuURL() + return nil + case user.FieldLinkedinURL: + m.ResetLinkedinURL() + return nil case user.FieldCreatedAt: m.ResetCreatedAt() return nil diff --git a/components/backend/ent/runtime/runtime.go b/components/backend/ent/runtime/runtime.go index 594b5a6a..2ae576f7 100644 --- a/components/backend/ent/runtime/runtime.go +++ b/components/backend/ent/runtime/runtime.go @@ -364,12 +364,24 @@ func init() { userDescEmail := userFields[3].Descriptor() // user.DefaultEmail holds the default value on creation for the email field. user.DefaultEmail = userDescEmail.Default.(string) + // userDescGithubURL is the schema descriptor for github_url field. + userDescGithubURL := userFields[4].Descriptor() + // user.DefaultGithubURL holds the default value on creation for the github_url field. + user.DefaultGithubURL = userDescGithubURL.Default.(string) + // userDescRenkuURL is the schema descriptor for renku_url field. + userDescRenkuURL := userFields[5].Descriptor() + // user.DefaultRenkuURL holds the default value on creation for the renku_url field. + user.DefaultRenkuURL = userDescRenkuURL.Default.(string) + // userDescLinkedinURL is the schema descriptor for linkedin_url field. + userDescLinkedinURL := userFields[6].Descriptor() + // user.DefaultLinkedinURL holds the default value on creation for the linkedin_url field. + user.DefaultLinkedinURL = userDescLinkedinURL.Default.(string) // userDescCreatedAt is the schema descriptor for created_at field. - userDescCreatedAt := userFields[4].Descriptor() + userDescCreatedAt := userFields[7].Descriptor() // user.DefaultCreatedAt holds the default value on creation for the created_at field. user.DefaultCreatedAt = userDescCreatedAt.Default.(func() time.Time) // userDescModifiedAt is the schema descriptor for modified_at field. - userDescModifiedAt := userFields[5].Descriptor() + userDescModifiedAt := userFields[8].Descriptor() // user.DefaultModifiedAt holds the default value on creation for the modified_at field. user.DefaultModifiedAt = userDescModifiedAt.Default.(func() time.Time) // user.UpdateDefaultModifiedAt holds the default value on update for the modified_at field. diff --git a/components/backend/ent/user.go b/components/backend/ent/user.go index 5a780f0b..9fdbeb7e 100644 --- a/components/backend/ent/user.go +++ b/components/backend/ent/user.go @@ -26,6 +26,12 @@ type User struct { DisplayName string `json:"display_name,omitempty"` // Email of the user, same as in Keycloak Email string `json:"email,omitempty"` + // Link to the user's GitHub profile, set by the user. + GithubURL string `json:"github_url,omitempty"` + // Link to the user's Renku profile, set by the user. + RenkuURL string `json:"renku_url,omitempty"` + // Link to the user's LinkedIn profile, set by the user. + LinkedinURL string `json:"linkedin_url,omitempty"` // Timestamp when the user was first seen. CreatedAt time.Time `json:"created_at,omitempty"` // Timestamp of the last profile update. @@ -356,7 +362,7 @@ func (*User) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { - case user.FieldUsername, user.FieldKeycloakID, user.FieldDisplayName, user.FieldEmail: + case user.FieldUsername, user.FieldKeycloakID, user.FieldDisplayName, user.FieldEmail, user.FieldGithubURL, user.FieldRenkuURL, user.FieldLinkedinURL: values[i] = new(sql.NullString) case user.FieldCreatedAt, user.FieldModifiedAt: values[i] = new(sql.NullTime) @@ -407,6 +413,24 @@ func (_m *User) assignValues(columns []string, values []any) error { } else if value.Valid { _m.Email = value.String } + case user.FieldGithubURL: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field github_url", values[i]) + } else if value.Valid { + _m.GithubURL = value.String + } + case user.FieldRenkuURL: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field renku_url", values[i]) + } else if value.Valid { + _m.RenkuURL = value.String + } + case user.FieldLinkedinURL: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field linkedin_url", values[i]) + } else if value.Valid { + _m.LinkedinURL = value.String + } case user.FieldCreatedAt: if value, ok := values[i].(*sql.NullTime); !ok { return fmt.Errorf("unexpected type %T for field created_at", values[i]) @@ -607,6 +631,15 @@ func (_m *User) String() string { builder.WriteString("email=") builder.WriteString(_m.Email) builder.WriteString(", ") + builder.WriteString("github_url=") + builder.WriteString(_m.GithubURL) + builder.WriteString(", ") + builder.WriteString("renku_url=") + builder.WriteString(_m.RenkuURL) + builder.WriteString(", ") + builder.WriteString("linkedin_url=") + builder.WriteString(_m.LinkedinURL) + builder.WriteString(", ") builder.WriteString("created_at=") builder.WriteString(_m.CreatedAt.Format(time.ANSIC)) builder.WriteString(", ") diff --git a/components/backend/ent/user/user.go b/components/backend/ent/user/user.go index 6c31c2e7..64498f73 100644 --- a/components/backend/ent/user/user.go +++ b/components/backend/ent/user/user.go @@ -23,6 +23,12 @@ const ( FieldDisplayName = "display_name" // FieldEmail holds the string denoting the email field in the database. FieldEmail = "email" + // FieldGithubURL holds the string denoting the github_url field in the database. + FieldGithubURL = "github_url" + // FieldRenkuURL holds the string denoting the renku_url field in the database. + FieldRenkuURL = "renku_url" + // FieldLinkedinURL holds the string denoting the linkedin_url field in the database. + FieldLinkedinURL = "linkedin_url" // FieldCreatedAt holds the string denoting the created_at field in the database. FieldCreatedAt = "created_at" // FieldModifiedAt holds the string denoting the modified_at field in the database. @@ -280,6 +286,9 @@ var Columns = []string{ FieldKeycloakID, FieldDisplayName, FieldEmail, + FieldGithubURL, + FieldRenkuURL, + FieldLinkedinURL, FieldCreatedAt, FieldModifiedAt, } @@ -319,6 +328,12 @@ var ( DefaultDisplayName string // DefaultEmail holds the default value on creation for the "email" field. DefaultEmail string + // DefaultGithubURL holds the default value on creation for the "github_url" field. + DefaultGithubURL string + // DefaultRenkuURL holds the default value on creation for the "renku_url" field. + DefaultRenkuURL string + // DefaultLinkedinURL holds the default value on creation for the "linkedin_url" field. + DefaultLinkedinURL string // DefaultCreatedAt holds the default value on creation for the "created_at" field. DefaultCreatedAt func() time.Time // DefaultModifiedAt holds the default value on creation for the "modified_at" field. @@ -357,6 +372,21 @@ func ByEmail(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldEmail, opts...).ToFunc() } +// ByGithubURL orders the results by the github_url field. +func ByGithubURL(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldGithubURL, opts...).ToFunc() +} + +// ByRenkuURL orders the results by the renku_url field. +func ByRenkuURL(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldRenkuURL, opts...).ToFunc() +} + +// ByLinkedinURL orders the results by the linkedin_url field. +func ByLinkedinURL(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldLinkedinURL, opts...).ToFunc() +} + // ByCreatedAt orders the results by the created_at field. func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() diff --git a/components/backend/ent/user/where.go b/components/backend/ent/user/where.go index 7c254b90..90aafbb0 100644 --- a/components/backend/ent/user/where.go +++ b/components/backend/ent/user/where.go @@ -76,6 +76,21 @@ func Email(v string) predicate.User { return predicate.User(sql.FieldEQ(FieldEmail, v)) } +// GithubURL applies equality check predicate on the "github_url" field. It's identical to GithubURLEQ. +func GithubURL(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldGithubURL, v)) +} + +// RenkuURL applies equality check predicate on the "renku_url" field. It's identical to RenkuURLEQ. +func RenkuURL(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldRenkuURL, v)) +} + +// LinkedinURL applies equality check predicate on the "linkedin_url" field. It's identical to LinkedinURLEQ. +func LinkedinURL(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldLinkedinURL, v)) +} + // CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. func CreatedAt(v time.Time) predicate.User { return predicate.User(sql.FieldEQ(FieldCreatedAt, v)) @@ -366,6 +381,231 @@ func EmailContainsFold(v string) predicate.User { return predicate.User(sql.FieldContainsFold(FieldEmail, v)) } +// GithubURLEQ applies the EQ predicate on the "github_url" field. +func GithubURLEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldGithubURL, v)) +} + +// GithubURLNEQ applies the NEQ predicate on the "github_url" field. +func GithubURLNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldGithubURL, v)) +} + +// GithubURLIn applies the In predicate on the "github_url" field. +func GithubURLIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldGithubURL, vs...)) +} + +// GithubURLNotIn applies the NotIn predicate on the "github_url" field. +func GithubURLNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldGithubURL, vs...)) +} + +// GithubURLGT applies the GT predicate on the "github_url" field. +func GithubURLGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldGithubURL, v)) +} + +// GithubURLGTE applies the GTE predicate on the "github_url" field. +func GithubURLGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldGithubURL, v)) +} + +// GithubURLLT applies the LT predicate on the "github_url" field. +func GithubURLLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldGithubURL, v)) +} + +// GithubURLLTE applies the LTE predicate on the "github_url" field. +func GithubURLLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldGithubURL, v)) +} + +// GithubURLContains applies the Contains predicate on the "github_url" field. +func GithubURLContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldGithubURL, v)) +} + +// GithubURLHasPrefix applies the HasPrefix predicate on the "github_url" field. +func GithubURLHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldGithubURL, v)) +} + +// GithubURLHasSuffix applies the HasSuffix predicate on the "github_url" field. +func GithubURLHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldGithubURL, v)) +} + +// GithubURLIsNil applies the IsNil predicate on the "github_url" field. +func GithubURLIsNil() predicate.User { + return predicate.User(sql.FieldIsNull(FieldGithubURL)) +} + +// GithubURLNotNil applies the NotNil predicate on the "github_url" field. +func GithubURLNotNil() predicate.User { + return predicate.User(sql.FieldNotNull(FieldGithubURL)) +} + +// GithubURLEqualFold applies the EqualFold predicate on the "github_url" field. +func GithubURLEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldGithubURL, v)) +} + +// GithubURLContainsFold applies the ContainsFold predicate on the "github_url" field. +func GithubURLContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldGithubURL, v)) +} + +// RenkuURLEQ applies the EQ predicate on the "renku_url" field. +func RenkuURLEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldRenkuURL, v)) +} + +// RenkuURLNEQ applies the NEQ predicate on the "renku_url" field. +func RenkuURLNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldRenkuURL, v)) +} + +// RenkuURLIn applies the In predicate on the "renku_url" field. +func RenkuURLIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldRenkuURL, vs...)) +} + +// RenkuURLNotIn applies the NotIn predicate on the "renku_url" field. +func RenkuURLNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldRenkuURL, vs...)) +} + +// RenkuURLGT applies the GT predicate on the "renku_url" field. +func RenkuURLGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldRenkuURL, v)) +} + +// RenkuURLGTE applies the GTE predicate on the "renku_url" field. +func RenkuURLGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldRenkuURL, v)) +} + +// RenkuURLLT applies the LT predicate on the "renku_url" field. +func RenkuURLLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldRenkuURL, v)) +} + +// RenkuURLLTE applies the LTE predicate on the "renku_url" field. +func RenkuURLLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldRenkuURL, v)) +} + +// RenkuURLContains applies the Contains predicate on the "renku_url" field. +func RenkuURLContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldRenkuURL, v)) +} + +// RenkuURLHasPrefix applies the HasPrefix predicate on the "renku_url" field. +func RenkuURLHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldRenkuURL, v)) +} + +// RenkuURLHasSuffix applies the HasSuffix predicate on the "renku_url" field. +func RenkuURLHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldRenkuURL, v)) +} + +// RenkuURLIsNil applies the IsNil predicate on the "renku_url" field. +func RenkuURLIsNil() predicate.User { + return predicate.User(sql.FieldIsNull(FieldRenkuURL)) +} + +// RenkuURLNotNil applies the NotNil predicate on the "renku_url" field. +func RenkuURLNotNil() predicate.User { + return predicate.User(sql.FieldNotNull(FieldRenkuURL)) +} + +// RenkuURLEqualFold applies the EqualFold predicate on the "renku_url" field. +func RenkuURLEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldRenkuURL, v)) +} + +// RenkuURLContainsFold applies the ContainsFold predicate on the "renku_url" field. +func RenkuURLContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldRenkuURL, v)) +} + +// LinkedinURLEQ applies the EQ predicate on the "linkedin_url" field. +func LinkedinURLEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldLinkedinURL, v)) +} + +// LinkedinURLNEQ applies the NEQ predicate on the "linkedin_url" field. +func LinkedinURLNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldLinkedinURL, v)) +} + +// LinkedinURLIn applies the In predicate on the "linkedin_url" field. +func LinkedinURLIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldLinkedinURL, vs...)) +} + +// LinkedinURLNotIn applies the NotIn predicate on the "linkedin_url" field. +func LinkedinURLNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldLinkedinURL, vs...)) +} + +// LinkedinURLGT applies the GT predicate on the "linkedin_url" field. +func LinkedinURLGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldLinkedinURL, v)) +} + +// LinkedinURLGTE applies the GTE predicate on the "linkedin_url" field. +func LinkedinURLGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldLinkedinURL, v)) +} + +// LinkedinURLLT applies the LT predicate on the "linkedin_url" field. +func LinkedinURLLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldLinkedinURL, v)) +} + +// LinkedinURLLTE applies the LTE predicate on the "linkedin_url" field. +func LinkedinURLLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldLinkedinURL, v)) +} + +// LinkedinURLContains applies the Contains predicate on the "linkedin_url" field. +func LinkedinURLContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldLinkedinURL, v)) +} + +// LinkedinURLHasPrefix applies the HasPrefix predicate on the "linkedin_url" field. +func LinkedinURLHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldLinkedinURL, v)) +} + +// LinkedinURLHasSuffix applies the HasSuffix predicate on the "linkedin_url" field. +func LinkedinURLHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldLinkedinURL, v)) +} + +// LinkedinURLIsNil applies the IsNil predicate on the "linkedin_url" field. +func LinkedinURLIsNil() predicate.User { + return predicate.User(sql.FieldIsNull(FieldLinkedinURL)) +} + +// LinkedinURLNotNil applies the NotNil predicate on the "linkedin_url" field. +func LinkedinURLNotNil() predicate.User { + return predicate.User(sql.FieldNotNull(FieldLinkedinURL)) +} + +// LinkedinURLEqualFold applies the EqualFold predicate on the "linkedin_url" field. +func LinkedinURLEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldLinkedinURL, v)) +} + +// LinkedinURLContainsFold applies the ContainsFold predicate on the "linkedin_url" field. +func LinkedinURLContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldLinkedinURL, v)) +} + // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.User { return predicate.User(sql.FieldEQ(FieldCreatedAt, v)) diff --git a/components/backend/ent/user_create.go b/components/backend/ent/user_create.go index 1e0a9bdf..3f3cf55c 100644 --- a/components/backend/ent/user_create.go +++ b/components/backend/ent/user_create.go @@ -78,6 +78,48 @@ func (_c *UserCreate) SetNillableEmail(v *string) *UserCreate { return _c } +// SetGithubURL sets the "github_url" field. +func (_c *UserCreate) SetGithubURL(v string) *UserCreate { + _c.mutation.SetGithubURL(v) + return _c +} + +// SetNillableGithubURL sets the "github_url" field if the given value is not nil. +func (_c *UserCreate) SetNillableGithubURL(v *string) *UserCreate { + if v != nil { + _c.SetGithubURL(*v) + } + return _c +} + +// SetRenkuURL sets the "renku_url" field. +func (_c *UserCreate) SetRenkuURL(v string) *UserCreate { + _c.mutation.SetRenkuURL(v) + return _c +} + +// SetNillableRenkuURL sets the "renku_url" field if the given value is not nil. +func (_c *UserCreate) SetNillableRenkuURL(v *string) *UserCreate { + if v != nil { + _c.SetRenkuURL(*v) + } + return _c +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (_c *UserCreate) SetLinkedinURL(v string) *UserCreate { + _c.mutation.SetLinkedinURL(v) + return _c +} + +// SetNillableLinkedinURL sets the "linkedin_url" field if the given value is not nil. +func (_c *UserCreate) SetNillableLinkedinURL(v *string) *UserCreate { + if v != nil { + _c.SetLinkedinURL(*v) + } + return _c +} + // SetCreatedAt sets the "created_at" field. func (_c *UserCreate) SetCreatedAt(v time.Time) *UserCreate { _c.mutation.SetCreatedAt(v) @@ -553,6 +595,18 @@ func (_c *UserCreate) defaults() { v := user.DefaultEmail _c.mutation.SetEmail(v) } + if _, ok := _c.mutation.GithubURL(); !ok { + v := user.DefaultGithubURL + _c.mutation.SetGithubURL(v) + } + if _, ok := _c.mutation.RenkuURL(); !ok { + v := user.DefaultRenkuURL + _c.mutation.SetRenkuURL(v) + } + if _, ok := _c.mutation.LinkedinURL(); !ok { + v := user.DefaultLinkedinURL + _c.mutation.SetLinkedinURL(v) + } if _, ok := _c.mutation.CreatedAt(); !ok { v := user.DefaultCreatedAt() _c.mutation.SetCreatedAt(v) @@ -638,6 +692,18 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { _spec.SetField(user.FieldEmail, field.TypeString, value) _node.Email = value } + if value, ok := _c.mutation.GithubURL(); ok { + _spec.SetField(user.FieldGithubURL, field.TypeString, value) + _node.GithubURL = value + } + if value, ok := _c.mutation.RenkuURL(); ok { + _spec.SetField(user.FieldRenkuURL, field.TypeString, value) + _node.RenkuURL = value + } + if value, ok := _c.mutation.LinkedinURL(); ok { + _spec.SetField(user.FieldLinkedinURL, field.TypeString, value) + _node.LinkedinURL = value + } if value, ok := _c.mutation.CreatedAt(); ok { _spec.SetField(user.FieldCreatedAt, field.TypeTime, value) _node.CreatedAt = value @@ -1182,6 +1248,60 @@ func (u *UserUpsert) ClearEmail() *UserUpsert { return u } +// SetGithubURL sets the "github_url" field. +func (u *UserUpsert) SetGithubURL(v string) *UserUpsert { + u.Set(user.FieldGithubURL, v) + return u +} + +// UpdateGithubURL sets the "github_url" field to the value that was provided on create. +func (u *UserUpsert) UpdateGithubURL() *UserUpsert { + u.SetExcluded(user.FieldGithubURL) + return u +} + +// ClearGithubURL clears the value of the "github_url" field. +func (u *UserUpsert) ClearGithubURL() *UserUpsert { + u.SetNull(user.FieldGithubURL) + return u +} + +// SetRenkuURL sets the "renku_url" field. +func (u *UserUpsert) SetRenkuURL(v string) *UserUpsert { + u.Set(user.FieldRenkuURL, v) + return u +} + +// UpdateRenkuURL sets the "renku_url" field to the value that was provided on create. +func (u *UserUpsert) UpdateRenkuURL() *UserUpsert { + u.SetExcluded(user.FieldRenkuURL) + return u +} + +// ClearRenkuURL clears the value of the "renku_url" field. +func (u *UserUpsert) ClearRenkuURL() *UserUpsert { + u.SetNull(user.FieldRenkuURL) + return u +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (u *UserUpsert) SetLinkedinURL(v string) *UserUpsert { + u.Set(user.FieldLinkedinURL, v) + return u +} + +// UpdateLinkedinURL sets the "linkedin_url" field to the value that was provided on create. +func (u *UserUpsert) UpdateLinkedinURL() *UserUpsert { + u.SetExcluded(user.FieldLinkedinURL) + return u +} + +// ClearLinkedinURL clears the value of the "linkedin_url" field. +func (u *UserUpsert) ClearLinkedinURL() *UserUpsert { + u.SetNull(user.FieldLinkedinURL) + return u +} + // SetModifiedAt sets the "modified_at" field. func (u *UserUpsert) SetModifiedAt(v time.Time) *UserUpsert { u.Set(user.FieldModifiedAt, v) @@ -1315,6 +1435,69 @@ func (u *UserUpsertOne) ClearEmail() *UserUpsertOne { }) } +// SetGithubURL sets the "github_url" field. +func (u *UserUpsertOne) SetGithubURL(v string) *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.SetGithubURL(v) + }) +} + +// UpdateGithubURL sets the "github_url" field to the value that was provided on create. +func (u *UserUpsertOne) UpdateGithubURL() *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.UpdateGithubURL() + }) +} + +// ClearGithubURL clears the value of the "github_url" field. +func (u *UserUpsertOne) ClearGithubURL() *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.ClearGithubURL() + }) +} + +// SetRenkuURL sets the "renku_url" field. +func (u *UserUpsertOne) SetRenkuURL(v string) *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.SetRenkuURL(v) + }) +} + +// UpdateRenkuURL sets the "renku_url" field to the value that was provided on create. +func (u *UserUpsertOne) UpdateRenkuURL() *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.UpdateRenkuURL() + }) +} + +// ClearRenkuURL clears the value of the "renku_url" field. +func (u *UserUpsertOne) ClearRenkuURL() *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.ClearRenkuURL() + }) +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (u *UserUpsertOne) SetLinkedinURL(v string) *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.SetLinkedinURL(v) + }) +} + +// UpdateLinkedinURL sets the "linkedin_url" field to the value that was provided on create. +func (u *UserUpsertOne) UpdateLinkedinURL() *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.UpdateLinkedinURL() + }) +} + +// ClearLinkedinURL clears the value of the "linkedin_url" field. +func (u *UserUpsertOne) ClearLinkedinURL() *UserUpsertOne { + return u.Update(func(s *UserUpsert) { + s.ClearLinkedinURL() + }) +} + // SetModifiedAt sets the "modified_at" field. func (u *UserUpsertOne) SetModifiedAt(v time.Time) *UserUpsertOne { return u.Update(func(s *UserUpsert) { @@ -1617,6 +1800,69 @@ func (u *UserUpsertBulk) ClearEmail() *UserUpsertBulk { }) } +// SetGithubURL sets the "github_url" field. +func (u *UserUpsertBulk) SetGithubURL(v string) *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.SetGithubURL(v) + }) +} + +// UpdateGithubURL sets the "github_url" field to the value that was provided on create. +func (u *UserUpsertBulk) UpdateGithubURL() *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.UpdateGithubURL() + }) +} + +// ClearGithubURL clears the value of the "github_url" field. +func (u *UserUpsertBulk) ClearGithubURL() *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.ClearGithubURL() + }) +} + +// SetRenkuURL sets the "renku_url" field. +func (u *UserUpsertBulk) SetRenkuURL(v string) *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.SetRenkuURL(v) + }) +} + +// UpdateRenkuURL sets the "renku_url" field to the value that was provided on create. +func (u *UserUpsertBulk) UpdateRenkuURL() *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.UpdateRenkuURL() + }) +} + +// ClearRenkuURL clears the value of the "renku_url" field. +func (u *UserUpsertBulk) ClearRenkuURL() *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.ClearRenkuURL() + }) +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (u *UserUpsertBulk) SetLinkedinURL(v string) *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.SetLinkedinURL(v) + }) +} + +// UpdateLinkedinURL sets the "linkedin_url" field to the value that was provided on create. +func (u *UserUpsertBulk) UpdateLinkedinURL() *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.UpdateLinkedinURL() + }) +} + +// ClearLinkedinURL clears the value of the "linkedin_url" field. +func (u *UserUpsertBulk) ClearLinkedinURL() *UserUpsertBulk { + return u.Update(func(s *UserUpsert) { + s.ClearLinkedinURL() + }) +} + // SetModifiedAt sets the "modified_at" field. func (u *UserUpsertBulk) SetModifiedAt(v time.Time) *UserUpsertBulk { return u.Update(func(s *UserUpsert) { diff --git a/components/backend/ent/user_update.go b/components/backend/ent/user_update.go index e4419bcc..4cc691e2 100644 --- a/components/backend/ent/user_update.go +++ b/components/backend/ent/user_update.go @@ -111,6 +111,66 @@ func (_u *UserUpdate) ClearEmail() *UserUpdate { return _u } +// SetGithubURL sets the "github_url" field. +func (_u *UserUpdate) SetGithubURL(v string) *UserUpdate { + _u.mutation.SetGithubURL(v) + return _u +} + +// SetNillableGithubURL sets the "github_url" field if the given value is not nil. +func (_u *UserUpdate) SetNillableGithubURL(v *string) *UserUpdate { + if v != nil { + _u.SetGithubURL(*v) + } + return _u +} + +// ClearGithubURL clears the value of the "github_url" field. +func (_u *UserUpdate) ClearGithubURL() *UserUpdate { + _u.mutation.ClearGithubURL() + return _u +} + +// SetRenkuURL sets the "renku_url" field. +func (_u *UserUpdate) SetRenkuURL(v string) *UserUpdate { + _u.mutation.SetRenkuURL(v) + return _u +} + +// SetNillableRenkuURL sets the "renku_url" field if the given value is not nil. +func (_u *UserUpdate) SetNillableRenkuURL(v *string) *UserUpdate { + if v != nil { + _u.SetRenkuURL(*v) + } + return _u +} + +// ClearRenkuURL clears the value of the "renku_url" field. +func (_u *UserUpdate) ClearRenkuURL() *UserUpdate { + _u.mutation.ClearRenkuURL() + return _u +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (_u *UserUpdate) SetLinkedinURL(v string) *UserUpdate { + _u.mutation.SetLinkedinURL(v) + return _u +} + +// SetNillableLinkedinURL sets the "linkedin_url" field if the given value is not nil. +func (_u *UserUpdate) SetNillableLinkedinURL(v *string) *UserUpdate { + if v != nil { + _u.SetLinkedinURL(*v) + } + return _u +} + +// ClearLinkedinURL clears the value of the "linkedin_url" field. +func (_u *UserUpdate) ClearLinkedinURL() *UserUpdate { + _u.mutation.ClearLinkedinURL() + return _u +} + // SetModifiedAt sets the "modified_at" field. func (_u *UserUpdate) SetModifiedAt(v time.Time) *UserUpdate { _u.mutation.SetModifiedAt(v) @@ -1134,6 +1194,24 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) { if _u.mutation.EmailCleared() { _spec.ClearField(user.FieldEmail, field.TypeString) } + if value, ok := _u.mutation.GithubURL(); ok { + _spec.SetField(user.FieldGithubURL, field.TypeString, value) + } + if _u.mutation.GithubURLCleared() { + _spec.ClearField(user.FieldGithubURL, field.TypeString) + } + if value, ok := _u.mutation.RenkuURL(); ok { + _spec.SetField(user.FieldRenkuURL, field.TypeString, value) + } + if _u.mutation.RenkuURLCleared() { + _spec.ClearField(user.FieldRenkuURL, field.TypeString) + } + if value, ok := _u.mutation.LinkedinURL(); ok { + _spec.SetField(user.FieldLinkedinURL, field.TypeString, value) + } + if _u.mutation.LinkedinURLCleared() { + _spec.ClearField(user.FieldLinkedinURL, field.TypeString) + } if value, ok := _u.mutation.ModifiedAt(); ok { _spec.SetField(user.FieldModifiedAt, field.TypeTime, value) } @@ -2419,6 +2497,66 @@ func (_u *UserUpdateOne) ClearEmail() *UserUpdateOne { return _u } +// SetGithubURL sets the "github_url" field. +func (_u *UserUpdateOne) SetGithubURL(v string) *UserUpdateOne { + _u.mutation.SetGithubURL(v) + return _u +} + +// SetNillableGithubURL sets the "github_url" field if the given value is not nil. +func (_u *UserUpdateOne) SetNillableGithubURL(v *string) *UserUpdateOne { + if v != nil { + _u.SetGithubURL(*v) + } + return _u +} + +// ClearGithubURL clears the value of the "github_url" field. +func (_u *UserUpdateOne) ClearGithubURL() *UserUpdateOne { + _u.mutation.ClearGithubURL() + return _u +} + +// SetRenkuURL sets the "renku_url" field. +func (_u *UserUpdateOne) SetRenkuURL(v string) *UserUpdateOne { + _u.mutation.SetRenkuURL(v) + return _u +} + +// SetNillableRenkuURL sets the "renku_url" field if the given value is not nil. +func (_u *UserUpdateOne) SetNillableRenkuURL(v *string) *UserUpdateOne { + if v != nil { + _u.SetRenkuURL(*v) + } + return _u +} + +// ClearRenkuURL clears the value of the "renku_url" field. +func (_u *UserUpdateOne) ClearRenkuURL() *UserUpdateOne { + _u.mutation.ClearRenkuURL() + return _u +} + +// SetLinkedinURL sets the "linkedin_url" field. +func (_u *UserUpdateOne) SetLinkedinURL(v string) *UserUpdateOne { + _u.mutation.SetLinkedinURL(v) + return _u +} + +// SetNillableLinkedinURL sets the "linkedin_url" field if the given value is not nil. +func (_u *UserUpdateOne) SetNillableLinkedinURL(v *string) *UserUpdateOne { + if v != nil { + _u.SetLinkedinURL(*v) + } + return _u +} + +// ClearLinkedinURL clears the value of the "linkedin_url" field. +func (_u *UserUpdateOne) ClearLinkedinURL() *UserUpdateOne { + _u.mutation.ClearLinkedinURL() + return _u +} + // SetModifiedAt sets the "modified_at" field. func (_u *UserUpdateOne) SetModifiedAt(v time.Time) *UserUpdateOne { _u.mutation.SetModifiedAt(v) @@ -3472,6 +3610,24 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) { if _u.mutation.EmailCleared() { _spec.ClearField(user.FieldEmail, field.TypeString) } + if value, ok := _u.mutation.GithubURL(); ok { + _spec.SetField(user.FieldGithubURL, field.TypeString, value) + } + if _u.mutation.GithubURLCleared() { + _spec.ClearField(user.FieldGithubURL, field.TypeString) + } + if value, ok := _u.mutation.RenkuURL(); ok { + _spec.SetField(user.FieldRenkuURL, field.TypeString, value) + } + if _u.mutation.RenkuURLCleared() { + _spec.ClearField(user.FieldRenkuURL, field.TypeString) + } + if value, ok := _u.mutation.LinkedinURL(); ok { + _spec.SetField(user.FieldLinkedinURL, field.TypeString, value) + } + if _u.mutation.LinkedinURLCleared() { + _spec.ClearField(user.FieldLinkedinURL, field.TypeString) + } if value, ok := _u.mutation.ModifiedAt(); ok { _spec.SetField(user.FieldModifiedAt, field.TypeTime, value) } diff --git a/components/backend/internal/middleware/rbac.go b/components/backend/internal/middleware/rbac.go index 5e82851a..7c9de84d 100644 --- a/components/backend/internal/middleware/rbac.go +++ b/components/backend/internal/middleware/rbac.go @@ -65,8 +65,9 @@ const ( Vote VoteCategory VoteResult - // Note: this is a dummy entry, there are no rules for users, since we only use admin checks with users. - // This is just here so we have something we can query on when checking admin permissions for the user table. + // Reading and listing users is admin-only, which needs no rule of its own. + // The one rule naming users lets anyone write their own profile: see + // WithUser. User ) @@ -178,6 +179,7 @@ func NewRBACEnforcer(cfg *config.Config) (*Enforcer, error) { const ( anyHackathonPath = "/hackathon/*" anyTeamPath = "/hackathon/*/team/*" + anyUserPath = "/user/*" ) func defaultPolicies(cfg *config.Config, e *casbin.Enforcer) error { @@ -245,6 +247,9 @@ func defaultPolicies(cfg *config.Config, e *casbin.Enforcer) error { {Owner.String(), anyHackathonPath, VoteResult.String(), Read.String()}, {Owner.String(), anyHackathonPath, VoteResult.String(), Write.String()}, {Owner.String(), anyHackathonPath, Vote.String(), Read.String()}, + // Anyone can edit a user profile. Which profile is decided by the + // handler, which only ever passes the caller's own WithUser domain. + {"*", anyUserPath, User.String(), Write.String()}, } // AddPoliciesEx adds what is missing and skips the rest. @@ -272,6 +277,12 @@ func teamDomainPath(domain, teamId string) string { return fmt.Sprintf("%s/team/%s", domain, teamId) } +// userDomainPath returns the domain path for one user's own resources, +// e.g. /user/