diff --git a/.gitignore b/.gitignore index 7a260ab..c946104 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,4 @@ overrides/ .pgp api/api api/graph/api/generated.go -api/graph/api/federation.go *_gen.go diff --git a/api/gqlgen.yml b/api/gqlgen.yml index b3463a1..8f61f81 100644 --- a/api/gqlgen.yml +++ b/api/gqlgen.yml @@ -8,9 +8,9 @@ exec: package: api # Uncomment to enable federation -federation: - filename: graph/api/federation.go - package: api +# federation: +# filename: graph/generated/federation.go +# package: generated # Where should any generated models go? model: diff --git a/api/graph/entity.resolvers.go b/api/graph/entity.resolvers.go deleted file mode 100644 index 2352727..0000000 --- a/api/graph/entity.resolvers.go +++ /dev/null @@ -1,25 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. - -import ( - "context" - - "git.sr.ht/~sircmpwn/meta.sr.ht/api/graph/api" - "git.sr.ht/~sircmpwn/meta.sr.ht/api/graph/model" - "git.sr.ht/~sircmpwn/meta.sr.ht/api/loaders" -) - -func (r *entityResolver) FindOAuthClientByUUID(ctx context.Context, uuid string) (*model.OAuthClient, error) { - return loaders.ForContext(ctx).OAuthClientsByUUID.Load(uuid) -} - -func (r *entityResolver) FindUserByID(ctx context.Context, id int) (*model.User, error) { - return loaders.ForContext(ctx).UsersByID.Load(id) -} - -// Entity returns api.EntityResolver implementation. -func (r *Resolver) Entity() api.EntityResolver { return &entityResolver{r} } - -type entityResolver struct{ *Resolver } diff --git a/api/graph/model/oauthclient.go b/api/graph/model/oauthclient.go index 3980c4f..bef9ebb 100644 --- a/api/graph/model/oauthclient.go +++ b/api/graph/model/oauthclient.go @@ -23,8 +23,6 @@ type OAuthClient struct { fields *database.ModelFields } -func (OAuthClient) IsEntity() {} - func (oc *OAuthClient) As(alias string) *OAuthClient { oc.alias = alias return oc diff --git a/api/graph/schema.graphqls b/api/graph/schema.graphqls index a1a0bf3..c68b49f 100644 --- a/api/graph/schema.graphqls +++ b/api/graph/schema.graphqls @@ -11,36 +11,36 @@ access token, and are not available to clients using OAuth 2.0 access tokens. directive @private on FIELD_DEFINITION """ -This is used to decorate fields which are for internal use, and are not +This used to decorate fields which are for internal use, and are not available to normal API users. """ directive @internal on FIELD_DEFINITION directive @anoninternal on FIELD_DEFINITION +""" +Used to provide a human-friendly description of an access scope. +""" +directive @scopehelp(details: String!) on ENUM_VALUE + enum AccessScope { - "Audit log" - AUDIT_LOG - "Billing history" - BILLING - "PGP keys" - PGP_KEYS - "SSH keys" - SSH_KEYS - "Profile information" - PROFILE + AUDIT_LOG @scopehelp(details: "audit log") + BILLING @scopehelp(details: "billing history") + PGP_KEYS @scopehelp(details: "PGP keys") + SSH_KEYS @scopehelp(details: "SSH keys") + PROFILE @scopehelp(details: "profile information") } enum AccessKind { - "Read-only" - RO - "Read and write" - RW + RO @scopehelp(details: "read") + RW @scopehelp(details: "read and write") } """ Decorates fields for which access requires a particular OAuth 2.0 scope with -read or write access. +read or write access. For the meta.sr.ht API, you have access to all public +information without any special permissions - user profile information, +public keys, and so on. """ directive @access(scope: AccessScope!, kind: AccessKind!) on FIELD_DEFINITION | ENUM_VALUE @@ -57,6 +57,17 @@ type Version { deprecationDate: Time } +interface Entity { + id: Int! + created: Time! + updated: Time! + """ + The canonical name of this entity. For users, this is their username + prefixed with '~'. Additional entity types will be supported in the future. + """ + canonicalName: String! +} + enum UserType { UNCONFIRMED ACTIVE_NON_PAYING @@ -67,7 +78,7 @@ enum UserType { SUSPENDED } -type User @key(fields: "id") { +type User implements Entity { id: Int! created: Time! updated: Time! @@ -133,7 +144,7 @@ type OAuthGrantRegistration { secret: String! } -type OAuthClient @key(fields: "uuid") { +type OAuthClient { id: Int! uuid: String! redirectUrl: String! @@ -142,7 +153,7 @@ type OAuthClient @key(fields: "uuid") { description: String url: String - owner: User! @access(scope: PROFILE, kind: RO) + owner: Entity! @access(scope: PROFILE, kind: RO) } type OAuthClientRegistration { @@ -320,7 +331,7 @@ type WebhookSubscriptionCursor { cursor: Cursor } -extend type Query { +type Query { "Returns API version information." version: Version! @@ -417,7 +428,7 @@ input ProfileWebhookInput { query: String! } -extend type Mutation { +type Mutation { updateUser(input: UserInput): User! @access(scope: PROFILE, kind: RW) createPGPKey(key: String!): PGPKey! @access(scope: PGP_KEYS, kind: RW) @@ -442,7 +453,7 @@ extend type Mutation { may be used to access details of the event which trigged the webhook. The query may not make any mutations. """ - createProfileWebhook(config: ProfileWebhookInput!): WebhookSubscription! + createWebhook(config: ProfileWebhookInput!): WebhookSubscription! """ Deletes a user profile webhook. Any events already queued may still be @@ -452,7 +463,7 @@ extend type Mutation { Manually deleting a webhook configured by a third-party client may cause unexpected behavior with the third-party integration. """ - deleteProfileWebhook(id: Int!): WebhookSubscription + deleteWebhook(id: Int!): WebhookSubscription ### ### ### The following resolvers are for internal use. ### diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go index 5cf2aaa..d81a4ba 100644 --- a/api/graph/schema.resolvers.go +++ b/api/graph/schema.resolvers.go @@ -486,7 +486,7 @@ func (r *mutationResolver) UpdateSSHKey(ctx context.Context, id int) (*model.SSH return &key, nil } -func (r *mutationResolver) CreateProfileWebhook(ctx context.Context, config model.ProfileWebhookInput) (model.WebhookSubscription, error) { +func (r *mutationResolver) CreateWebhook(ctx context.Context, config model.ProfileWebhookInput) (model.WebhookSubscription, error) { schema := server.ForContext(ctx).Schema if err := corewebhooks.Validate(schema, config.Query); err != nil { return nil, err @@ -563,7 +563,7 @@ func (r *mutationResolver) CreateProfileWebhook(ctx context.Context, config mode return &sub, nil } -func (r *mutationResolver) DeleteProfileWebhook(ctx context.Context, id int) (model.WebhookSubscription, error) { +func (r *mutationResolver) DeleteWebhook(ctx context.Context, id int) (model.WebhookSubscription, error) { var sub model.ProfileWebhookSubscription filter, err := corewebhooks.FilterWebhooks(ctx) @@ -1167,7 +1167,7 @@ func (r *mutationResolver) SendEmailNotification(ctx context.Context, subject st return err == nil, err } -func (r *oAuthClientResolver) Owner(ctx context.Context, obj *model.OAuthClient) (*model.User, error) { +func (r *oAuthClientResolver) Owner(ctx context.Context, obj *model.OAuthClient) (model.Entity, error) { return loaders.ForContext(ctx).UsersByID.Load(obj.OwnerID) }