diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ab6e104..c6683fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## v2.0.0 + +* [BREAKING] Changed `$sequence` type from `int` to `string` for rows and documents +* Added `NewProject` and `NewWebhooks` client constructors +* Added impersonation helpers `WithImpersonateUserId`, `WithImpersonateUserEmail`, `WithImpersonateUserPhone` +* Added avatar URL helpers: `GetBrowserURL`, `GetCreditCardURL`, `GetFaviconURL`, `GetFlagURL`, `GetImageURL`, `GetInitialsURL`, `GetQRURL`, `GetScreenshotURL` +* Updated README badge to API version 1.9.0 + ## v1.0.0 * Breaking: Activate parameter was removed from CreateDeployment; use WithCreateDeploymentActivate. @@ -8,7 +16,7 @@ * Added: TTL option to list operations for documents and rows. * Updated: Document and Row sequence comments to reflect sequence IDs. -## 0.17.0 +## v0.17.0 * Added new Activities service to the Go SDK with a NewActivities constructor to access Activities endpoints. * Extended Databases attribute APIs to support encryption: introduced Encrypt option for Longtext, Mediumtext, Text, and Varchar attributes, along with corresponding New/Create option builders (WithCreateLongtextAttributeEncrypt, WithCreateMediumtextAttributeEncrypt, WithCreateTextAttributeEncrypt, WithCreateVarcharAttributeEncrypt) and wiring to send the encrypt parameter when enabled. diff --git a/README.md b/README.md index 8ad82ca3..4e1a34f2 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite Go SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-go.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-1.8.1-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.9.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK is compatible with Appwrite server version 1.8.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-go/releases).** +**This SDK is compatible with Appwrite server version 1.9.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-go/releases).** Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Go SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) diff --git a/appwrite/appwrite.go b/appwrite/appwrite.go index 0f2d7b9e..1f965dbb 100644 --- a/appwrite/appwrite.go +++ b/appwrite/appwrite.go @@ -14,12 +14,14 @@ import ( "github.com/appwrite/sdk-for-go/health" "github.com/appwrite/sdk-for-go/locale" "github.com/appwrite/sdk-for-go/messaging" + "github.com/appwrite/sdk-for-go/project" "github.com/appwrite/sdk-for-go/sites" "github.com/appwrite/sdk-for-go/storage" "github.com/appwrite/sdk-for-go/tablesdb" "github.com/appwrite/sdk-for-go/teams" "github.com/appwrite/sdk-for-go/tokens" "github.com/appwrite/sdk-for-go/users" + "github.com/appwrite/sdk-for-go/webhooks" ) func NewAccount(clt client.Client) *account.Account { @@ -52,6 +54,9 @@ func NewLocale(clt client.Client) *locale.Locale { func NewMessaging(clt client.Client) *messaging.Messaging { return messaging.New(clt) } +func NewProject(clt client.Client) *project.Project { + return project.New(clt) +} func NewSites(clt client.Client) *sites.Sites { return sites.New(clt) } @@ -70,6 +75,9 @@ func NewTokens(clt client.Client) *tokens.Tokens { func NewUsers(clt client.Client) *users.Users { return users.New(clt) } +func NewWebhooks(clt client.Client) *webhooks.Webhooks { + return webhooks.New(clt) +} // NewClient initializes a new Appwrite client with a given timeout func NewClient(optionalSetters ...client.ClientOption) client.Client { @@ -167,3 +175,30 @@ func WithForwardedUserAgent(value string) client.ClientOption { return nil } } +// Helper method to construct NewClient() +// +// Impersonate a user by ID on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data. +func WithImpersonateUserId(value string) client.ClientOption { + return func(clt *client.Client) error { + clt.Headers["X-Appwrite-Impersonate-User-Id"] = value + return nil + } +} +// Helper method to construct NewClient() +// +// Impersonate a user by email on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data. +func WithImpersonateUserEmail(value string) client.ClientOption { + return func(clt *client.Client) error { + clt.Headers["X-Appwrite-Impersonate-User-Email"] = value + return nil + } +} +// Helper method to construct NewClient() +// +// Impersonate a user by phone on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data. +func WithImpersonateUserPhone(value string) client.ClientOption { + return func(clt *client.Client) error { + clt.Headers["X-Appwrite-Impersonate-User-Phone"] = value + return nil + } +} diff --git a/avatars/avatars.go b/avatars/avatars.go index 0492f3bb..4027c4de 100644 --- a/avatars/avatars.go +++ b/avatars/avatars.go @@ -4,6 +4,8 @@ import ( "encoding/json" "errors" "github.com/appwrite/sdk-for-go/client" + "net/url" + "fmt" "strings" ) @@ -107,6 +109,43 @@ func (srv *Avatars) GetBrowser(Code string, optionalSetters ...GetBrowserOption) return &parsed, nil } +// GetBrowserURL you can use this endpoint to show different browser icons to +// your users. The code argument receives the browser code as it appears in +// your user [GET +// /account/sessions](https://appwrite.io/docs/references/cloud/client-web/account#getSessions) +// endpoint. Use width, height and quality arguments to change the output +// settings. +// +// When one dimension is specified and the other is 0, the image is scaled +// with preserved aspect ratio. If both dimensions are 0, the API provides an +// image at source quality. If dimensions are not specified, the default size +// of image returned is 100x100px. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetBrowserURL(Code string, optionalSetters ...GetBrowserOption) (*string, error) { + r := strings.NewReplacer("{code}", Code) + path := r.Replace("/avatars/browsers/{code}") + options := GetBrowserOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + if options.enabledSetters["Quality"] { + q.Set("quality", fmt.Sprintf("%v", options.Quality)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetCreditCardOptions struct { Width int Height int @@ -193,6 +232,40 @@ func (srv *Avatars) GetCreditCard(Code string, optionalSetters ...GetCreditCardO return &parsed, nil } +// GetCreditCardURL the credit card endpoint will return you the icon of the +// credit card provider you need. Use width, height and quality arguments to +// change the output settings. +// +// When one dimension is specified and the other is 0, the image is scaled +// with preserved aspect ratio. If both dimensions are 0, the API provides an +// image at source quality. If dimensions are not specified, the default size +// of image returned is 100x100px. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetCreditCardURL(Code string, optionalSetters ...GetCreditCardOption) (*string, error) { + r := strings.NewReplacer("{code}", Code) + path := r.Replace("/avatars/credit-cards/{code}") + options := GetCreditCardOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + if options.enabledSetters["Quality"] { + q.Set("quality", fmt.Sprintf("%v", options.Quality)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} // GetFavicon use this endpoint to fetch the favorite icon (AKA favicon) of // any remote website URL. @@ -228,6 +301,23 @@ func (srv *Avatars) GetFavicon(Url string)(*[]byte, error) { return &parsed, nil } +// GetFaviconURL use this endpoint to fetch the favorite icon (AKA favicon) of +// any remote website URL. +// +// This endpoint does not follow HTTP redirects. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetFaviconURL(Url string) (*string, error) { + path := "/avatars/favicon" + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + q.Set("url", fmt.Sprintf("%v", Url)) + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetFlagOptions struct { Width int Height int @@ -316,6 +406,42 @@ func (srv *Avatars) GetFlag(Code string, optionalSetters ...GetFlagOption)(*[]by return &parsed, nil } +// GetFlagURL you can use this endpoint to show different country flags icons +// to your users. The code argument receives the 2 letter country code. Use +// width, height and quality arguments to change the output settings. Country +// codes follow the [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) +// standard. +// +// When one dimension is specified and the other is 0, the image is scaled +// with preserved aspect ratio. If both dimensions are 0, the API provides an +// image at source quality. If dimensions are not specified, the default size +// of image returned is 100x100px. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetFlagURL(Code string, optionalSetters ...GetFlagOption) (*string, error) { + r := strings.NewReplacer("{code}", Code) + path := r.Replace("/avatars/flags/{code}") + options := GetFlagOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + if options.enabledSetters["Quality"] { + q.Set("quality", fmt.Sprintf("%v", options.Quality)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetImageOptions struct { Width int Height int @@ -393,6 +519,40 @@ func (srv *Avatars) GetImage(Url string, optionalSetters ...GetImageOption)(*[]b return &parsed, nil } +// GetImageURL use this endpoint to fetch a remote image URL and crop it to +// any image size you want. This endpoint is very useful if you need to crop +// and display remote images in your app or in case you want to make sure a +// 3rd party image is properly served using a TLS protocol. +// +// When one dimension is specified and the other is 0, the image is scaled +// with preserved aspect ratio. If both dimensions are 0, the API provides an +// image at source quality. If dimensions are not specified, the default size +// of image returned is 400x400px. +// +// This endpoint does not follow HTTP redirects. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetImageURL(Url string, optionalSetters ...GetImageOption) (*string, error) { + path := "/avatars/image" + options := GetImageOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + q.Set("url", fmt.Sprintf("%v", Url)) + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetInitialsOptions struct { Name string Width int @@ -495,6 +655,49 @@ func (srv *Avatars) GetInitials(optionalSetters ...GetInitialsOption)(*[]byte, e return &parsed, nil } +// GetInitialsURL use this endpoint to show your user initials avatar icon on +// your website or app. By default, this route will try to print your +// logged-in user name or email initials. You can also overwrite the user name +// if you pass the 'name' parameter. If no name is given and no user is +// logged, an empty avatar will be returned. +// +// You can use the color and background params to change the avatar colors. By +// default, a random theme will be selected. The random theme will persist for +// the user's initials when reloading the same theme will always return for +// the same initials. +// +// When one dimension is specified and the other is 0, the image is scaled +// with preserved aspect ratio. If both dimensions are 0, the API provides an +// image at source quality. If dimensions are not specified, the default size +// of image returned is 100x100px. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetInitialsURL(optionalSetters ...GetInitialsOption) (*string, error) { + path := "/avatars/initials" + options := GetInitialsOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Name"] { + q.Set("name", fmt.Sprintf("%v", options.Name)) + } + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + if options.enabledSetters["Background"] { + q.Set("background", fmt.Sprintf("%v", options.Background)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetQROptions struct { Size int Margin int @@ -574,6 +777,34 @@ func (srv *Avatars) GetQR(Text string, optionalSetters ...GetQROption)(*[]byte, return &parsed, nil } +// GetQRURL converts a given plain text to a QR code image. You can use the +// query parameters to change the size and style of the resulting image. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetQRURL(Text string, optionalSetters ...GetQROption) (*string, error) { + path := "/avatars/qr" + options := GetQROptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + q.Set("text", fmt.Sprintf("%v", Text)) + if options.enabledSetters["Size"] { + q.Set("size", fmt.Sprintf("%v", options.Size)) + } + if options.enabledSetters["Margin"] { + q.Set("margin", fmt.Sprintf("%v", options.Margin)) + } + if options.enabledSetters["Download"] { + q.Set("download", fmt.Sprintf("%v", options.Download)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetScreenshotOptions struct { Headers interface{} ViewportWidth int @@ -838,3 +1069,88 @@ func (srv *Avatars) GetScreenshot(Url string, optionalSetters ...GetScreenshotOp return &parsed, nil } +// GetScreenshotURL use this endpoint to capture a screenshot of any website +// URL. This endpoint uses a headless browser to render the webpage and +// capture it as an image. +// +// You can configure the browser viewport size, theme, user agent, +// geolocation, permissions, and more. Capture either just the viewport or the +// full page scroll. +// +// When width and height are specified, the image is resized accordingly. If +// both dimensions are 0, the API provides an image at original size. If +// dimensions are not specified, the default viewport size is 1280x720px. +// Returns the URL for the resource instead of the content. +func (srv *Avatars) GetScreenshotURL(Url string, optionalSetters ...GetScreenshotOption) (*string, error) { + path := "/avatars/screenshots" + options := GetScreenshotOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + q.Set("url", fmt.Sprintf("%v", Url)) + if options.enabledSetters["Headers"] { + q.Set("headers", fmt.Sprintf("%v", options.Headers)) + } + if options.enabledSetters["ViewportWidth"] { + q.Set("viewportWidth", fmt.Sprintf("%v", options.ViewportWidth)) + } + if options.enabledSetters["ViewportHeight"] { + q.Set("viewportHeight", fmt.Sprintf("%v", options.ViewportHeight)) + } + if options.enabledSetters["Scale"] { + q.Set("scale", fmt.Sprintf("%v", options.Scale)) + } + if options.enabledSetters["Theme"] { + q.Set("theme", fmt.Sprintf("%v", options.Theme)) + } + if options.enabledSetters["UserAgent"] { + q.Set("userAgent", fmt.Sprintf("%v", options.UserAgent)) + } + if options.enabledSetters["Fullpage"] { + q.Set("fullpage", fmt.Sprintf("%v", options.Fullpage)) + } + if options.enabledSetters["Locale"] { + q.Set("locale", fmt.Sprintf("%v", options.Locale)) + } + if options.enabledSetters["Timezone"] { + q.Set("timezone", fmt.Sprintf("%v", options.Timezone)) + } + if options.enabledSetters["Latitude"] { + q.Set("latitude", fmt.Sprintf("%v", options.Latitude)) + } + if options.enabledSetters["Longitude"] { + q.Set("longitude", fmt.Sprintf("%v", options.Longitude)) + } + if options.enabledSetters["Accuracy"] { + q.Set("accuracy", fmt.Sprintf("%v", options.Accuracy)) + } + if options.enabledSetters["Touch"] { + q.Set("touch", fmt.Sprintf("%v", options.Touch)) + } + if options.enabledSetters["Permissions"] { + q.Set("permissions", fmt.Sprintf("%v", options.Permissions)) + } + if options.enabledSetters["Sleep"] { + q.Set("sleep", fmt.Sprintf("%v", options.Sleep)) + } + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + if options.enabledSetters["Quality"] { + q.Set("quality", fmt.Sprintf("%v", options.Quality)) + } + if options.enabledSetters["Output"] { + q.Set("output", fmt.Sprintf("%v", options.Output)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} diff --git a/client/client.go b/client/client.go index f3373104..0cf9bb3e 100644 --- a/client/client.go +++ b/client/client.go @@ -73,12 +73,12 @@ type Client struct { // Initialize a new Appwrite client with a given timeout func New(optionalSetters ...ClientOption) Client { headers := map[string]string{ - "X-Appwrite-Response-Format" : "1.8.0", - "user-agent" : fmt.Sprintf("AppwriteGoSDK/v1.0.0 (%s; %s)", runtime.GOOS, runtime.GOARCH), + "X-Appwrite-Response-Format" : "1.9.0", + "user-agent" : fmt.Sprintf("AppwriteGoSDK/v2.0.0 (%s; %s)", runtime.GOOS, runtime.GOARCH), "x-sdk-name": "Go", "x-sdk-platform": "server", "x-sdk-language": "go", - "x-sdk-version": "v1.0.0", + "x-sdk-version": "v2.0.0", } httpClient, err := GetDefaultClient(defaultTimeout) if err != nil { @@ -125,6 +125,11 @@ func (client *Client) AddHeader(key string, value string) { client.Headers[key] = value } +// GetEndpoint returns the client's current endpoint +func (client *Client) GetEndpoint() string { + return client.Endpoint +} + func isFileUpload(headers map[string]interface{}) bool { contentType, ok := headers["content-type"].(string) if ok { diff --git a/docs/examples/functions/create.md b/docs/examples/functions/create.md index b75cbe83..673c84d4 100644 --- a/docs/examples/functions/create.md +++ b/docs/examples/functions/create.md @@ -33,6 +33,8 @@ response, error := service.Create( functions.WithCreateProviderBranch(""), functions.WithCreateProviderSilentMode(false), functions.WithCreateProviderRootDirectory(""), - functions.WithCreateSpecification(""), + functions.WithCreateBuildSpecification(""), + functions.WithCreateRuntimeSpecification(""), + functions.WithCreateDeploymentRetention(0), ) ``` diff --git a/docs/examples/functions/update.md b/docs/examples/functions/update.md index 2038abcc..6f89a995 100644 --- a/docs/examples/functions/update.md +++ b/docs/examples/functions/update.md @@ -33,6 +33,8 @@ response, error := service.Update( functions.WithUpdateProviderBranch(""), functions.WithUpdateProviderSilentMode(false), functions.WithUpdateProviderRootDirectory(""), - functions.WithUpdateSpecification(""), + functions.WithUpdateBuildSpecification(""), + functions.WithUpdateRuntimeSpecification(""), + functions.WithUpdateDeploymentRetention(0), ) ``` diff --git a/docs/examples/project/create-variable.md b/docs/examples/project/create-variable.md new file mode 100644 index 00000000..84284e72 --- /dev/null +++ b/docs/examples/project/create-variable.md @@ -0,0 +1,24 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/project" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := project.New(client) + +response, error := service.CreateVariable( + "", + "", + "", + project.WithCreateVariableSecret(false), +) +``` diff --git a/docs/examples/project/delete-variable.md b/docs/examples/project/delete-variable.md new file mode 100644 index 00000000..fd5da105 --- /dev/null +++ b/docs/examples/project/delete-variable.md @@ -0,0 +1,21 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/project" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := project.New(client) + +response, error := service.DeleteVariable( + "", +) +``` diff --git a/docs/examples/project/get-variable.md b/docs/examples/project/get-variable.md new file mode 100644 index 00000000..1a765804 --- /dev/null +++ b/docs/examples/project/get-variable.md @@ -0,0 +1,21 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/project" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := project.New(client) + +response, error := service.GetVariable( + "", +) +``` diff --git a/docs/examples/project/list-variables.md b/docs/examples/project/list-variables.md new file mode 100644 index 00000000..15657c6a --- /dev/null +++ b/docs/examples/project/list-variables.md @@ -0,0 +1,22 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/project" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := project.New(client) + +response, error := service.ListVariables( + project.WithListVariablesQueries([]interface{}{}), + project.WithListVariablesTotal(false), +) +``` diff --git a/docs/examples/project/update-variable.md b/docs/examples/project/update-variable.md new file mode 100644 index 00000000..3da119f0 --- /dev/null +++ b/docs/examples/project/update-variable.md @@ -0,0 +1,24 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/project" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := project.New(client) + +response, error := service.UpdateVariable( + "", + project.WithUpdateVariableKey(""), + project.WithUpdateVariableValue(""), + project.WithUpdateVariableSecret(false), +) +``` diff --git a/docs/examples/sites/create.md b/docs/examples/sites/create.md index a44a8d18..ba161003 100644 --- a/docs/examples/sites/create.md +++ b/docs/examples/sites/create.md @@ -25,6 +25,7 @@ response, error := service.Create( sites.WithCreateTimeout(1), sites.WithCreateInstallCommand(""), sites.WithCreateBuildCommand(""), + sites.WithCreateStartCommand(""), sites.WithCreateOutputDirectory(""), sites.WithCreateAdapter("static"), sites.WithCreateInstallationId(""), @@ -33,6 +34,8 @@ response, error := service.Create( sites.WithCreateProviderBranch(""), sites.WithCreateProviderSilentMode(false), sites.WithCreateProviderRootDirectory(""), - sites.WithCreateSpecification(""), + sites.WithCreateBuildSpecification(""), + sites.WithCreateRuntimeSpecification(""), + sites.WithCreateDeploymentRetention(0), ) ``` diff --git a/docs/examples/sites/update.md b/docs/examples/sites/update.md index 0f322edb..f20edc4e 100644 --- a/docs/examples/sites/update.md +++ b/docs/examples/sites/update.md @@ -24,6 +24,7 @@ response, error := service.Update( sites.WithUpdateTimeout(1), sites.WithUpdateInstallCommand(""), sites.WithUpdateBuildCommand(""), + sites.WithUpdateStartCommand(""), sites.WithUpdateOutputDirectory(""), sites.WithUpdateBuildRuntime("node-14.5"), sites.WithUpdateAdapter("static"), @@ -33,6 +34,8 @@ response, error := service.Update( sites.WithUpdateProviderBranch(""), sites.WithUpdateProviderSilentMode(false), sites.WithUpdateProviderRootDirectory(""), - sites.WithUpdateSpecification(""), + sites.WithUpdateBuildSpecification(""), + sites.WithUpdateRuntimeSpecification(""), + sites.WithUpdateDeploymentRetention(0), ) ``` diff --git a/docs/examples/users/update-impersonator.md b/docs/examples/users/update-impersonator.md new file mode 100644 index 00000000..0e0445f7 --- /dev/null +++ b/docs/examples/users/update-impersonator.md @@ -0,0 +1,22 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/users" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := users.New(client) + +response, error := service.UpdateImpersonator( + "", + false, +) +``` diff --git a/docs/examples/webhooks/create.md b/docs/examples/webhooks/create.md new file mode 100644 index 00000000..14484c56 --- /dev/null +++ b/docs/examples/webhooks/create.md @@ -0,0 +1,28 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/webhooks" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := webhooks.New(client) + +response, error := service.Create( + "", + "", + "", + []interface{}{}, + webhooks.WithCreateEnabled(false), + webhooks.WithCreateSecurity(false), + webhooks.WithCreateHttpUser(""), + webhooks.WithCreateHttpPass(""), +) +``` diff --git a/docs/examples/webhooks/delete.md b/docs/examples/webhooks/delete.md new file mode 100644 index 00000000..c193e7b1 --- /dev/null +++ b/docs/examples/webhooks/delete.md @@ -0,0 +1,21 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/webhooks" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := webhooks.New(client) + +response, error := service.Delete( + "", +) +``` diff --git a/docs/examples/webhooks/get.md b/docs/examples/webhooks/get.md new file mode 100644 index 00000000..ce01f93b --- /dev/null +++ b/docs/examples/webhooks/get.md @@ -0,0 +1,21 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/webhooks" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := webhooks.New(client) + +response, error := service.Get( + "", +) +``` diff --git a/docs/examples/webhooks/list.md b/docs/examples/webhooks/list.md new file mode 100644 index 00000000..e2d4a851 --- /dev/null +++ b/docs/examples/webhooks/list.md @@ -0,0 +1,22 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/webhooks" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := webhooks.New(client) + +response, error := service.List( + webhooks.WithListQueries([]interface{}{}), + webhooks.WithListTotal(false), +) +``` diff --git a/docs/examples/webhooks/update-signature.md b/docs/examples/webhooks/update-signature.md new file mode 100644 index 00000000..0c73804f --- /dev/null +++ b/docs/examples/webhooks/update-signature.md @@ -0,0 +1,21 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/webhooks" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := webhooks.New(client) + +response, error := service.UpdateSignature( + "", +) +``` diff --git a/docs/examples/webhooks/update.md b/docs/examples/webhooks/update.md new file mode 100644 index 00000000..91f3f2e9 --- /dev/null +++ b/docs/examples/webhooks/update.md @@ -0,0 +1,28 @@ +```go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/webhooks" +) + +client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") + client.WithProject("") + client.WithKey("") +) + +service := webhooks.New(client) + +response, error := service.Update( + "", + "", + "", + []interface{}{}, + webhooks.WithUpdateEnabled(false), + webhooks.WithUpdateSecurity(false), + webhooks.WithUpdateHttpUser(""), + webhooks.WithUpdateHttpPass(""), +) +``` diff --git a/functions/functions.go b/functions/functions.go index 9ba882b3..84ebc1a5 100644 --- a/functions/functions.go +++ b/functions/functions.go @@ -6,6 +6,8 @@ import ( "github.com/appwrite/sdk-for-go/client" "github.com/appwrite/sdk-for-go/models" "github.com/appwrite/sdk-for-go/file" + "net/url" + "fmt" "strings" ) @@ -114,7 +116,9 @@ type CreateOptions struct { ProviderBranch string ProviderSilentMode bool ProviderRootDirectory string - Specification string + BuildSpecification string + RuntimeSpecification string + DeploymentRetention int enabledSetters map[string]bool } func (options CreateOptions) New() *CreateOptions { @@ -133,7 +137,9 @@ func (options CreateOptions) New() *CreateOptions { "ProviderBranch": false, "ProviderSilentMode": false, "ProviderRootDirectory": false, - "Specification": false, + "BuildSpecification": false, + "RuntimeSpecification": false, + "DeploymentRetention": false, } return &options } @@ -222,10 +228,22 @@ func (srv *Functions) WithCreateProviderRootDirectory(v string) CreateOption { o.enabledSetters["ProviderRootDirectory"] = true } } -func (srv *Functions) WithCreateSpecification(v string) CreateOption { +func (srv *Functions) WithCreateBuildSpecification(v string) CreateOption { return func(o *CreateOptions) { - o.Specification = v - o.enabledSetters["Specification"] = true + o.BuildSpecification = v + o.enabledSetters["BuildSpecification"] = true + } +} +func (srv *Functions) WithCreateRuntimeSpecification(v string) CreateOption { + return func(o *CreateOptions) { + o.RuntimeSpecification = v + o.enabledSetters["RuntimeSpecification"] = true + } +} +func (srv *Functions) WithCreateDeploymentRetention(v int) CreateOption { + return func(o *CreateOptions) { + o.DeploymentRetention = v + o.enabledSetters["DeploymentRetention"] = true } } @@ -285,8 +303,14 @@ func (srv *Functions) Create(FunctionId string, Name string, Runtime string, opt if options.enabledSetters["ProviderRootDirectory"] { params["providerRootDirectory"] = options.ProviderRootDirectory } - if options.enabledSetters["Specification"] { - params["specification"] = options.Specification + if options.enabledSetters["BuildSpecification"] { + params["buildSpecification"] = options.BuildSpecification + } + if options.enabledSetters["RuntimeSpecification"] { + params["runtimeSpecification"] = options.RuntimeSpecification + } + if options.enabledSetters["DeploymentRetention"] { + params["deploymentRetention"] = options.DeploymentRetention } headers := map[string]interface{}{ "content-type": "application/json", @@ -431,7 +455,9 @@ type UpdateOptions struct { ProviderBranch string ProviderSilentMode bool ProviderRootDirectory string - Specification string + BuildSpecification string + RuntimeSpecification string + DeploymentRetention int enabledSetters map[string]bool } func (options UpdateOptions) New() *UpdateOptions { @@ -451,7 +477,9 @@ func (options UpdateOptions) New() *UpdateOptions { "ProviderBranch": false, "ProviderSilentMode": false, "ProviderRootDirectory": false, - "Specification": false, + "BuildSpecification": false, + "RuntimeSpecification": false, + "DeploymentRetention": false, } return &options } @@ -546,10 +574,22 @@ func (srv *Functions) WithUpdateProviderRootDirectory(v string) UpdateOption { o.enabledSetters["ProviderRootDirectory"] = true } } -func (srv *Functions) WithUpdateSpecification(v string) UpdateOption { +func (srv *Functions) WithUpdateBuildSpecification(v string) UpdateOption { return func(o *UpdateOptions) { - o.Specification = v - o.enabledSetters["Specification"] = true + o.BuildSpecification = v + o.enabledSetters["BuildSpecification"] = true + } +} +func (srv *Functions) WithUpdateRuntimeSpecification(v string) UpdateOption { + return func(o *UpdateOptions) { + o.RuntimeSpecification = v + o.enabledSetters["RuntimeSpecification"] = true + } +} +func (srv *Functions) WithUpdateDeploymentRetention(v int) UpdateOption { + return func(o *UpdateOptions) { + o.DeploymentRetention = v + o.enabledSetters["DeploymentRetention"] = true } } @@ -609,8 +649,14 @@ func (srv *Functions) Update(FunctionId string, Name string, optionalSetters ... if options.enabledSetters["ProviderRootDirectory"] { params["providerRootDirectory"] = options.ProviderRootDirectory } - if options.enabledSetters["Specification"] { - params["specification"] = options.Specification + if options.enabledSetters["BuildSpecification"] { + params["buildSpecification"] = options.BuildSpecification + } + if options.enabledSetters["RuntimeSpecification"] { + params["runtimeSpecification"] = options.RuntimeSpecification + } + if options.enabledSetters["DeploymentRetention"] { + params["deploymentRetention"] = options.DeploymentRetention } headers := map[string]interface{}{ "content-type": "application/json", @@ -1202,6 +1248,30 @@ func (srv *Functions) GetDeploymentDownload(FunctionId string, DeploymentId stri return &parsed, nil } +// GetDeploymentDownloadURL get a function deployment content by its unique +// ID. The endpoint response return with a 'Content-Disposition: attachment' +// header that tells the browser to start downloading the file to user +// downloads directory. +// Returns the URL for the resource instead of the content. +func (srv *Functions) GetDeploymentDownloadURL(FunctionId string, DeploymentId string, optionalSetters ...GetDeploymentDownloadOption) (*string, error) { + r := strings.NewReplacer("{functionId}", FunctionId, "{deploymentId}", DeploymentId) + path := r.Replace("/functions/{functionId}/deployments/{deploymentId}/download") + options := GetDeploymentDownloadOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Type"] { + q.Set("type", fmt.Sprintf("%v", options.Type)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} // UpdateDeploymentStatus cancel an ongoing function deployment build. If the // build is already in progress, it will be stopped and marked as canceled. If diff --git a/health/health.go b/health/health.go index 873f3975..6cbe5af2 100644 --- a/health/health.go +++ b/health/health.go @@ -364,118 +364,6 @@ func (srv *Health) GetQueueAudits(optionalSetters ...GetQueueAuditsOption)(*mode } return &parsed, nil -} -type GetQueueBillingProjectAggregationOptions struct { - Threshold int - enabledSetters map[string]bool -} -func (options GetQueueBillingProjectAggregationOptions) New() *GetQueueBillingProjectAggregationOptions { - options.enabledSetters = map[string]bool{ - "Threshold": false, - } - return &options -} -type GetQueueBillingProjectAggregationOption func(*GetQueueBillingProjectAggregationOptions) -func (srv *Health) WithGetQueueBillingProjectAggregationThreshold(v int) GetQueueBillingProjectAggregationOption { - return func(o *GetQueueBillingProjectAggregationOptions) { - o.Threshold = v - o.enabledSetters["Threshold"] = true - } -} - -// GetQueueBillingProjectAggregation get billing project aggregation queue. -func (srv *Health) GetQueueBillingProjectAggregation(optionalSetters ...GetQueueBillingProjectAggregationOption)(*models.HealthQueue, error) { - path := "/health/queue/billing-project-aggregation" - options := GetQueueBillingProjectAggregationOptions{}.New() - for _, opt := range optionalSetters { - opt(options) - } - params := map[string]interface{}{} - if options.enabledSetters["Threshold"] { - params["threshold"] = options.Threshold - } - headers := map[string]interface{}{ - } - - resp, err := srv.client.Call("GET", path, headers, params) - if err != nil { - return nil, err - } - if strings.HasPrefix(resp.Type, "application/json") { - bytes := []byte(resp.Result.(string)) - - parsed := models.HealthQueue{}.New(bytes) - - err = json.Unmarshal(bytes, parsed) - if err != nil { - return nil, err - } - - return parsed, nil - } - var parsed models.HealthQueue - parsed, ok := resp.Result.(models.HealthQueue) - if !ok { - return nil, errors.New("unexpected response type") - } - return &parsed, nil - -} -type GetQueueBillingTeamAggregationOptions struct { - Threshold int - enabledSetters map[string]bool -} -func (options GetQueueBillingTeamAggregationOptions) New() *GetQueueBillingTeamAggregationOptions { - options.enabledSetters = map[string]bool{ - "Threshold": false, - } - return &options -} -type GetQueueBillingTeamAggregationOption func(*GetQueueBillingTeamAggregationOptions) -func (srv *Health) WithGetQueueBillingTeamAggregationThreshold(v int) GetQueueBillingTeamAggregationOption { - return func(o *GetQueueBillingTeamAggregationOptions) { - o.Threshold = v - o.enabledSetters["Threshold"] = true - } -} - -// GetQueueBillingTeamAggregation get billing team aggregation queue. -func (srv *Health) GetQueueBillingTeamAggregation(optionalSetters ...GetQueueBillingTeamAggregationOption)(*models.HealthQueue, error) { - path := "/health/queue/billing-team-aggregation" - options := GetQueueBillingTeamAggregationOptions{}.New() - for _, opt := range optionalSetters { - opt(options) - } - params := map[string]interface{}{} - if options.enabledSetters["Threshold"] { - params["threshold"] = options.Threshold - } - headers := map[string]interface{}{ - } - - resp, err := srv.client.Call("GET", path, headers, params) - if err != nil { - return nil, err - } - if strings.HasPrefix(resp.Type, "application/json") { - bytes := []byte(resp.Result.(string)) - - parsed := models.HealthQueue{}.New(bytes) - - err = json.Unmarshal(bytes, parsed) - if err != nil { - return nil, err - } - - return parsed, nil - } - var parsed models.HealthQueue - parsed, ok := resp.Result.(models.HealthQueue) - if !ok { - return nil, errors.New("unexpected response type") - } - return &parsed, nil - } type GetQueueBuildsOptions struct { Threshold int @@ -533,62 +421,6 @@ func (srv *Health) GetQueueBuilds(optionalSetters ...GetQueueBuildsOption)(*mode } return &parsed, nil -} -type GetQueuePriorityBuildsOptions struct { - Threshold int - enabledSetters map[string]bool -} -func (options GetQueuePriorityBuildsOptions) New() *GetQueuePriorityBuildsOptions { - options.enabledSetters = map[string]bool{ - "Threshold": false, - } - return &options -} -type GetQueuePriorityBuildsOption func(*GetQueuePriorityBuildsOptions) -func (srv *Health) WithGetQueuePriorityBuildsThreshold(v int) GetQueuePriorityBuildsOption { - return func(o *GetQueuePriorityBuildsOptions) { - o.Threshold = v - o.enabledSetters["Threshold"] = true - } -} - -// GetQueuePriorityBuilds get the priority builds queue size. -func (srv *Health) GetQueuePriorityBuilds(optionalSetters ...GetQueuePriorityBuildsOption)(*models.HealthQueue, error) { - path := "/health/queue/builds-priority" - options := GetQueuePriorityBuildsOptions{}.New() - for _, opt := range optionalSetters { - opt(options) - } - params := map[string]interface{}{} - if options.enabledSetters["Threshold"] { - params["threshold"] = options.Threshold - } - headers := map[string]interface{}{ - } - - resp, err := srv.client.Call("GET", path, headers, params) - if err != nil { - return nil, err - } - if strings.HasPrefix(resp.Type, "application/json") { - bytes := []byte(resp.Result.(string)) - - parsed := models.HealthQueue{}.New(bytes) - - err = json.Unmarshal(bytes, parsed) - if err != nil { - return nil, err - } - - return parsed, nil - } - var parsed models.HealthQueue - parsed, ok := resp.Result.(models.HealthQueue) - if !ok { - return nil, errors.New("unexpected response type") - } - return &parsed, nil - } type GetQueueCertificatesOptions struct { Threshold int @@ -1115,62 +947,6 @@ func (srv *Health) GetQueueMigrations(optionalSetters ...GetQueueMigrationsOptio } return &parsed, nil -} -type GetQueueRegionManagerOptions struct { - Threshold int - enabledSetters map[string]bool -} -func (options GetQueueRegionManagerOptions) New() *GetQueueRegionManagerOptions { - options.enabledSetters = map[string]bool{ - "Threshold": false, - } - return &options -} -type GetQueueRegionManagerOption func(*GetQueueRegionManagerOptions) -func (srv *Health) WithGetQueueRegionManagerThreshold(v int) GetQueueRegionManagerOption { - return func(o *GetQueueRegionManagerOptions) { - o.Threshold = v - o.enabledSetters["Threshold"] = true - } -} - -// GetQueueRegionManager get region manager queue. -func (srv *Health) GetQueueRegionManager(optionalSetters ...GetQueueRegionManagerOption)(*models.HealthQueue, error) { - path := "/health/queue/region-manager" - options := GetQueueRegionManagerOptions{}.New() - for _, opt := range optionalSetters { - opt(options) - } - params := map[string]interface{}{} - if options.enabledSetters["Threshold"] { - params["threshold"] = options.Threshold - } - headers := map[string]interface{}{ - } - - resp, err := srv.client.Call("GET", path, headers, params) - if err != nil { - return nil, err - } - if strings.HasPrefix(resp.Type, "application/json") { - bytes := []byte(resp.Result.(string)) - - parsed := models.HealthQueue{}.New(bytes) - - err = json.Unmarshal(bytes, parsed) - if err != nil { - return nil, err - } - - return parsed, nil - } - var parsed models.HealthQueue - parsed, ok := resp.Result.(models.HealthQueue) - if !ok { - return nil, errors.New("unexpected response type") - } - return &parsed, nil - } type GetQueueStatsResourcesOptions struct { Threshold int @@ -1285,62 +1061,6 @@ func (srv *Health) GetQueueUsage(optionalSetters ...GetQueueUsageOption)(*models } return &parsed, nil -} -type GetQueueThreatsOptions struct { - Threshold int - enabledSetters map[string]bool -} -func (options GetQueueThreatsOptions) New() *GetQueueThreatsOptions { - options.enabledSetters = map[string]bool{ - "Threshold": false, - } - return &options -} -type GetQueueThreatsOption func(*GetQueueThreatsOptions) -func (srv *Health) WithGetQueueThreatsThreshold(v int) GetQueueThreatsOption { - return func(o *GetQueueThreatsOptions) { - o.Threshold = v - o.enabledSetters["Threshold"] = true - } -} - -// GetQueueThreats get threats queue. -func (srv *Health) GetQueueThreats(optionalSetters ...GetQueueThreatsOption)(*models.HealthQueue, error) { - path := "/health/queue/threats" - options := GetQueueThreatsOptions{}.New() - for _, opt := range optionalSetters { - opt(options) - } - params := map[string]interface{}{} - if options.enabledSetters["Threshold"] { - params["threshold"] = options.Threshold - } - headers := map[string]interface{}{ - } - - resp, err := srv.client.Call("GET", path, headers, params) - if err != nil { - return nil, err - } - if strings.HasPrefix(resp.Type, "application/json") { - bytes := []byte(resp.Result.(string)) - - parsed := models.HealthQueue{}.New(bytes) - - err = json.Unmarshal(bytes, parsed) - if err != nil { - return nil, err - } - - return parsed, nil - } - var parsed models.HealthQueue - parsed, ok := resp.Result.(models.HealthQueue) - if !ok { - return nil, errors.New("unexpected response type") - } - return &parsed, nil - } type GetQueueWebhooksOptions struct { Threshold int diff --git a/models/document.go b/models/document.go index 1dcaa7a3..955f75da 100644 --- a/models/document.go +++ b/models/document.go @@ -10,7 +10,7 @@ type Document struct { // Document ID. Id string `json:"$id"` // Document sequence ID. - Sequence int `json:"$sequence"` + Sequence string `json:"$sequence"` // Collection ID. CollectionId string `json:"$collectionId"` // Database ID. diff --git a/models/function.go b/models/function.go index 18e817b8..26b0359c 100644 --- a/models/function.go +++ b/models/function.go @@ -29,6 +29,9 @@ type Function struct { Logging bool `json:"logging"` // Function execution and build runtime. Runtime string `json:"runtime"` + // How many days to keep the non-active deployments before they will be + // automatically deleted. + DeploymentRetention int `json:"deploymentRetention"` // Function's active deployment ID. DeploymentId string `json:"deploymentId"` // Active deployment creation date in ISO 8601 format. @@ -68,8 +71,10 @@ type Function struct { // silence mode, no comments will be posted on the repository pull or merge // requests ProviderSilentMode bool `json:"providerSilentMode"` - // Machine specification for builds and executions. - Specification string `json:"specification"` + // Machine specification for deployment builds. + BuildSpecification string `json:"buildSpecification"` + // Machine specification for executions. + RuntimeSpecification string `json:"runtimeSpecification"` // Used by Decode() method data []byte diff --git a/models/log.go b/models/log.go index 027f3bad..734ae0b8 100644 --- a/models/log.go +++ b/models/log.go @@ -9,11 +9,14 @@ import ( type Log struct { // Event name. Event string `json:"event"` - // User ID. + // User ID of the actor recorded for this log. During impersonation, this is + // the original impersonator, not the impersonated target user. UserId string `json:"userId"` - // User Email. + // User email of the actor recorded for this log. During impersonation, this + // is the original impersonator. UserEmail string `json:"userEmail"` - // User Name. + // User name of the actor recorded for this log. During impersonation, this is + // the original impersonator. UserName string `json:"userName"` // API mode when event triggered. Mode string `json:"mode"` diff --git a/models/row.go b/models/row.go index cf3343d6..5b61961a 100644 --- a/models/row.go +++ b/models/row.go @@ -10,7 +10,7 @@ type Row struct { // Row ID. Id string `json:"$id"` // Row sequence ID. - Sequence int `json:"$sequence"` + Sequence string `json:"$sequence"` // Table ID. TableId string `json:"$tableId"` // Database ID. diff --git a/models/site.go b/models/site.go index e332f260..542ec016 100644 --- a/models/site.go +++ b/models/site.go @@ -27,6 +27,9 @@ type Site struct { Logging bool `json:"logging"` // Site framework. Framework string `json:"framework"` + // How many days to keep the non-active deployments before they will be + // automatically deleted. + DeploymentRetention int `json:"deploymentRetention"` // Site's active deployment ID. DeploymentId string `json:"deploymentId"` // Active deployment creation date in ISO 8601 format. @@ -50,6 +53,8 @@ type Site struct { InstallCommand string `json:"installCommand"` // The build command used to build the site. BuildCommand string `json:"buildCommand"` + // Custom command to use when starting site runtime. + StartCommand string `json:"startCommand"` // The directory where the site build output is located. OutputDirectory string `json:"outputDirectory"` // Site VCS (Version Control System) installation id. @@ -64,8 +69,10 @@ type Site struct { // silence mode, no comments will be posted on the repository pull or merge // requests ProviderSilentMode bool `json:"providerSilentMode"` - // Machine specification for builds and executions. - Specification string `json:"specification"` + // Machine specification for deployment builds. + BuildSpecification string `json:"buildSpecification"` + // Machine specification for SSR executions. + RuntimeSpecification string `json:"runtimeSpecification"` // Site build runtime. BuildRuntime string `json:"buildRuntime"` // Site framework adapter. diff --git a/models/user.go b/models/user.go index e70c8ad4..e924624d 100644 --- a/models/user.go +++ b/models/user.go @@ -47,6 +47,13 @@ type User struct { // Most recent access date in ISO 8601 format. This attribute is only updated // again after 24 hours. AccessedAt string `json:"accessedAt"` + // Whether the user can impersonate other users. + Impersonator bool `json:"impersonator"` + // ID of the original actor performing the impersonation. Present only when + // the current request is impersonating another user. Internal audit logs + // attribute the action to this user, while the impersonated target is + // recorded only in internal audit payload data. + ImpersonatorUserId string `json:"impersonatorUserId"` // Used by Decode() method data []byte diff --git a/models/webhook.go b/models/webhook.go new file mode 100644 index 00000000..b9acbe14 --- /dev/null +++ b/models/webhook.go @@ -0,0 +1,57 @@ +package models + +import ( + "encoding/json" + "errors" +) + +// Webhook Model +type Webhook struct { + // Webhook ID. + Id string `json:"$id"` + // Webhook creation date in ISO 8601 format. + CreatedAt string `json:"$createdAt"` + // Webhook update date in ISO 8601 format. + UpdatedAt string `json:"$updatedAt"` + // Webhook name. + Name string `json:"name"` + // Webhook URL endpoint. + Url string `json:"url"` + // Webhook trigger events. + Events []string `json:"events"` + // Indicated if SSL / TLS Certificate verification is enabled. + Security bool `json:"security"` + // HTTP basic authentication username. + HttpUser string `json:"httpUser"` + // HTTP basic authentication password. + HttpPass string `json:"httpPass"` + // Signature key which can be used to validated incoming + SignatureKey string `json:"signatureKey"` + // Indicates if this webhook is enabled. + Enabled bool `json:"enabled"` + // Webhook error logs from the most recent failure. + Logs string `json:"logs"` + // Number of consecutive failed webhook attempts. + Attempts int `json:"attempts"` + + // Used by Decode() method + data []byte +} + +func (model Webhook) New(data []byte) *Webhook { + model.data = data + return &model +} + +func (model *Webhook) Decode(value interface{}) error { + if len(model.data) <= 0 { + return errors.New("method Decode() cannot be used on nested struct") + } + + err := json.Unmarshal(model.data, value) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/models/webhook_list.go b/models/webhook_list.go new file mode 100644 index 00000000..047de6a7 --- /dev/null +++ b/models/webhook_list.go @@ -0,0 +1,35 @@ +package models + +import ( + "encoding/json" + "errors" +) + +// WebhooksList Model +type WebhookList struct { + // Total number of webhooks that matched your query. + Total int `json:"total"` + // List of webhooks. + Webhooks []Webhook `json:"webhooks"` + + // Used by Decode() method + data []byte +} + +func (model WebhookList) New(data []byte) *WebhookList { + model.data = data + return &model +} + +func (model *WebhookList) Decode(value interface{}) error { + if len(model.data) <= 0 { + return errors.New("method Decode() cannot be used on nested struct") + } + + err := json.Unmarshal(model.data, value) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/project/project.go b/project/project.go new file mode 100644 index 00000000..e887c917 --- /dev/null +++ b/project/project.go @@ -0,0 +1,298 @@ +package project + +import ( + "encoding/json" + "errors" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/models" + "strings" +) + +// Project service +type Project struct { + client client.Client +} + +func New(clt client.Client) *Project { + return &Project{ + client: clt, + } +} + +type ListVariablesOptions struct { + Queries []string + Total bool + enabledSetters map[string]bool +} +func (options ListVariablesOptions) New() *ListVariablesOptions { + options.enabledSetters = map[string]bool{ + "Queries": false, + "Total": false, + } + return &options +} +type ListVariablesOption func(*ListVariablesOptions) +func (srv *Project) WithListVariablesQueries(v []string) ListVariablesOption { + return func(o *ListVariablesOptions) { + o.Queries = v + o.enabledSetters["Queries"] = true + } +} +func (srv *Project) WithListVariablesTotal(v bool) ListVariablesOption { + return func(o *ListVariablesOptions) { + o.Total = v + o.enabledSetters["Total"] = true + } +} + +// ListVariables get a list of all project environment variables. +func (srv *Project) ListVariables(optionalSetters ...ListVariablesOption)(*models.VariableList, error) { + path := "/project/variables" + options := ListVariablesOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + params := map[string]interface{}{} + if options.enabledSetters["Queries"] { + params["queries"] = options.Queries + } + if options.enabledSetters["Total"] { + params["total"] = options.Total + } + headers := map[string]interface{}{ + } + + resp, err := srv.client.Call("GET", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.VariableList{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.VariableList + parsed, ok := resp.Result.(models.VariableList) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} +type CreateVariableOptions struct { + Secret bool + enabledSetters map[string]bool +} +func (options CreateVariableOptions) New() *CreateVariableOptions { + options.enabledSetters = map[string]bool{ + "Secret": false, + } + return &options +} +type CreateVariableOption func(*CreateVariableOptions) +func (srv *Project) WithCreateVariableSecret(v bool) CreateVariableOption { + return func(o *CreateVariableOptions) { + o.Secret = v + o.enabledSetters["Secret"] = true + } +} + +// CreateVariable create a new project environment variable. These variables +// can be accessed by all functions and sites in the project. +func (srv *Project) CreateVariable(VariableId string, Key string, Value string, optionalSetters ...CreateVariableOption)(*models.Variable, error) { + path := "/project/variables" + options := CreateVariableOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + params := map[string]interface{}{} + params["variableId"] = VariableId + params["key"] = Key + params["value"] = Value + if options.enabledSetters["Secret"] { + params["secret"] = options.Secret + } + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("POST", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Variable{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Variable + parsed, ok := resp.Result.(models.Variable) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} + +// GetVariable get a variable by its unique ID. +func (srv *Project) GetVariable(VariableId string)(*models.Variable, error) { + r := strings.NewReplacer("{variableId}", VariableId) + path := r.Replace("/project/variables/{variableId}") + params := map[string]interface{}{} + params["variableId"] = VariableId + headers := map[string]interface{}{ + } + + resp, err := srv.client.Call("GET", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Variable{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Variable + parsed, ok := resp.Result.(models.Variable) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} +type UpdateVariableOptions struct { + Key string + Value string + Secret bool + enabledSetters map[string]bool +} +func (options UpdateVariableOptions) New() *UpdateVariableOptions { + options.enabledSetters = map[string]bool{ + "Key": false, + "Value": false, + "Secret": false, + } + return &options +} +type UpdateVariableOption func(*UpdateVariableOptions) +func (srv *Project) WithUpdateVariableKey(v string) UpdateVariableOption { + return func(o *UpdateVariableOptions) { + o.Key = v + o.enabledSetters["Key"] = true + } +} +func (srv *Project) WithUpdateVariableValue(v string) UpdateVariableOption { + return func(o *UpdateVariableOptions) { + o.Value = v + o.enabledSetters["Value"] = true + } +} +func (srv *Project) WithUpdateVariableSecret(v bool) UpdateVariableOption { + return func(o *UpdateVariableOptions) { + o.Secret = v + o.enabledSetters["Secret"] = true + } +} + +// UpdateVariable update variable by its unique ID. +func (srv *Project) UpdateVariable(VariableId string, optionalSetters ...UpdateVariableOption)(*models.Variable, error) { + r := strings.NewReplacer("{variableId}", VariableId) + path := r.Replace("/project/variables/{variableId}") + options := UpdateVariableOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + params := map[string]interface{}{} + params["variableId"] = VariableId + if options.enabledSetters["Key"] { + params["key"] = options.Key + } + if options.enabledSetters["Value"] { + params["value"] = options.Value + } + if options.enabledSetters["Secret"] { + params["secret"] = options.Secret + } + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("PUT", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Variable{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Variable + parsed, ok := resp.Result.(models.Variable) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} + +// DeleteVariable delete a variable by its unique ID. +func (srv *Project) DeleteVariable(VariableId string)(*interface{}, error) { + r := strings.NewReplacer("{variableId}", VariableId) + path := r.Replace("/project/variables/{variableId}") + params := map[string]interface{}{} + params["variableId"] = VariableId + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("DELETE", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + var parsed interface{} + + err = json.Unmarshal(bytes, &parsed) + if err != nil { + return nil, err + } + return &parsed, nil + } + var parsed interface{} + parsed, ok := resp.Result.(interface{}) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} diff --git a/sites/sites.go b/sites/sites.go index 567b62e6..b5fc27e3 100644 --- a/sites/sites.go +++ b/sites/sites.go @@ -6,6 +6,8 @@ import ( "github.com/appwrite/sdk-for-go/client" "github.com/appwrite/sdk-for-go/models" "github.com/appwrite/sdk-for-go/file" + "net/url" + "fmt" "strings" ) @@ -105,6 +107,7 @@ type CreateOptions struct { Timeout int InstallCommand string BuildCommand string + StartCommand string OutputDirectory string Adapter string InstallationId string @@ -113,7 +116,9 @@ type CreateOptions struct { ProviderBranch string ProviderSilentMode bool ProviderRootDirectory string - Specification string + BuildSpecification string + RuntimeSpecification string + DeploymentRetention int enabledSetters map[string]bool } func (options CreateOptions) New() *CreateOptions { @@ -123,6 +128,7 @@ func (options CreateOptions) New() *CreateOptions { "Timeout": false, "InstallCommand": false, "BuildCommand": false, + "StartCommand": false, "OutputDirectory": false, "Adapter": false, "InstallationId": false, @@ -131,7 +137,9 @@ func (options CreateOptions) New() *CreateOptions { "ProviderBranch": false, "ProviderSilentMode": false, "ProviderRootDirectory": false, - "Specification": false, + "BuildSpecification": false, + "RuntimeSpecification": false, + "DeploymentRetention": false, } return &options } @@ -166,6 +174,12 @@ func (srv *Sites) WithCreateBuildCommand(v string) CreateOption { o.enabledSetters["BuildCommand"] = true } } +func (srv *Sites) WithCreateStartCommand(v string) CreateOption { + return func(o *CreateOptions) { + o.StartCommand = v + o.enabledSetters["StartCommand"] = true + } +} func (srv *Sites) WithCreateOutputDirectory(v string) CreateOption { return func(o *CreateOptions) { o.OutputDirectory = v @@ -214,10 +228,22 @@ func (srv *Sites) WithCreateProviderRootDirectory(v string) CreateOption { o.enabledSetters["ProviderRootDirectory"] = true } } -func (srv *Sites) WithCreateSpecification(v string) CreateOption { +func (srv *Sites) WithCreateBuildSpecification(v string) CreateOption { + return func(o *CreateOptions) { + o.BuildSpecification = v + o.enabledSetters["BuildSpecification"] = true + } +} +func (srv *Sites) WithCreateRuntimeSpecification(v string) CreateOption { + return func(o *CreateOptions) { + o.RuntimeSpecification = v + o.enabledSetters["RuntimeSpecification"] = true + } +} +func (srv *Sites) WithCreateDeploymentRetention(v int) CreateOption { return func(o *CreateOptions) { - o.Specification = v - o.enabledSetters["Specification"] = true + o.DeploymentRetention = v + o.enabledSetters["DeploymentRetention"] = true } } @@ -248,6 +274,9 @@ func (srv *Sites) Create(SiteId string, Name string, Framework string, BuildRunt if options.enabledSetters["BuildCommand"] { params["buildCommand"] = options.BuildCommand } + if options.enabledSetters["StartCommand"] { + params["startCommand"] = options.StartCommand + } if options.enabledSetters["OutputDirectory"] { params["outputDirectory"] = options.OutputDirectory } @@ -272,8 +301,14 @@ func (srv *Sites) Create(SiteId string, Name string, Framework string, BuildRunt if options.enabledSetters["ProviderRootDirectory"] { params["providerRootDirectory"] = options.ProviderRootDirectory } - if options.enabledSetters["Specification"] { - params["specification"] = options.Specification + if options.enabledSetters["BuildSpecification"] { + params["buildSpecification"] = options.BuildSpecification + } + if options.enabledSetters["RuntimeSpecification"] { + params["runtimeSpecification"] = options.RuntimeSpecification + } + if options.enabledSetters["DeploymentRetention"] { + params["deploymentRetention"] = options.DeploymentRetention } headers := map[string]interface{}{ "content-type": "application/json", @@ -408,6 +443,7 @@ type UpdateOptions struct { Timeout int InstallCommand string BuildCommand string + StartCommand string OutputDirectory string BuildRuntime string Adapter string @@ -417,7 +453,9 @@ type UpdateOptions struct { ProviderBranch string ProviderSilentMode bool ProviderRootDirectory string - Specification string + BuildSpecification string + RuntimeSpecification string + DeploymentRetention int enabledSetters map[string]bool } func (options UpdateOptions) New() *UpdateOptions { @@ -427,6 +465,7 @@ func (options UpdateOptions) New() *UpdateOptions { "Timeout": false, "InstallCommand": false, "BuildCommand": false, + "StartCommand": false, "OutputDirectory": false, "BuildRuntime": false, "Adapter": false, @@ -436,7 +475,9 @@ func (options UpdateOptions) New() *UpdateOptions { "ProviderBranch": false, "ProviderSilentMode": false, "ProviderRootDirectory": false, - "Specification": false, + "BuildSpecification": false, + "RuntimeSpecification": false, + "DeploymentRetention": false, } return &options } @@ -471,6 +512,12 @@ func (srv *Sites) WithUpdateBuildCommand(v string) UpdateOption { o.enabledSetters["BuildCommand"] = true } } +func (srv *Sites) WithUpdateStartCommand(v string) UpdateOption { + return func(o *UpdateOptions) { + o.StartCommand = v + o.enabledSetters["StartCommand"] = true + } +} func (srv *Sites) WithUpdateOutputDirectory(v string) UpdateOption { return func(o *UpdateOptions) { o.OutputDirectory = v @@ -525,10 +572,22 @@ func (srv *Sites) WithUpdateProviderRootDirectory(v string) UpdateOption { o.enabledSetters["ProviderRootDirectory"] = true } } -func (srv *Sites) WithUpdateSpecification(v string) UpdateOption { +func (srv *Sites) WithUpdateBuildSpecification(v string) UpdateOption { + return func(o *UpdateOptions) { + o.BuildSpecification = v + o.enabledSetters["BuildSpecification"] = true + } +} +func (srv *Sites) WithUpdateRuntimeSpecification(v string) UpdateOption { return func(o *UpdateOptions) { - o.Specification = v - o.enabledSetters["Specification"] = true + o.RuntimeSpecification = v + o.enabledSetters["RuntimeSpecification"] = true + } +} +func (srv *Sites) WithUpdateDeploymentRetention(v int) UpdateOption { + return func(o *UpdateOptions) { + o.DeploymentRetention = v + o.enabledSetters["DeploymentRetention"] = true } } @@ -559,6 +618,9 @@ func (srv *Sites) Update(SiteId string, Name string, Framework string, optionalS if options.enabledSetters["BuildCommand"] { params["buildCommand"] = options.BuildCommand } + if options.enabledSetters["StartCommand"] { + params["startCommand"] = options.StartCommand + } if options.enabledSetters["OutputDirectory"] { params["outputDirectory"] = options.OutputDirectory } @@ -586,8 +648,14 @@ func (srv *Sites) Update(SiteId string, Name string, Framework string, optionalS if options.enabledSetters["ProviderRootDirectory"] { params["providerRootDirectory"] = options.ProviderRootDirectory } - if options.enabledSetters["Specification"] { - params["specification"] = options.Specification + if options.enabledSetters["BuildSpecification"] { + params["buildSpecification"] = options.BuildSpecification + } + if options.enabledSetters["RuntimeSpecification"] { + params["runtimeSpecification"] = options.RuntimeSpecification + } + if options.enabledSetters["DeploymentRetention"] { + params["deploymentRetention"] = options.DeploymentRetention } headers := map[string]interface{}{ "content-type": "application/json", @@ -1168,6 +1236,30 @@ func (srv *Sites) GetDeploymentDownload(SiteId string, DeploymentId string, opti return &parsed, nil } +// GetDeploymentDownloadURL get a site deployment content by its unique ID. +// The endpoint response return with a 'Content-Disposition: attachment' +// header that tells the browser to start downloading the file to user +// downloads directory. +// Returns the URL for the resource instead of the content. +func (srv *Sites) GetDeploymentDownloadURL(SiteId string, DeploymentId string, optionalSetters ...GetDeploymentDownloadOption) (*string, error) { + r := strings.NewReplacer("{siteId}", SiteId, "{deploymentId}", DeploymentId) + path := r.Replace("/sites/{siteId}/deployments/{deploymentId}/download") + options := GetDeploymentDownloadOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Type"] { + q.Set("type", fmt.Sprintf("%v", options.Type)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} // UpdateDeploymentStatus cancel an ongoing site deployment build. If the // build is already in progress, it will be stopped and marked as canceled. If diff --git a/storage/storage.go b/storage/storage.go index 0a19a5ee..d7d2ffe3 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -6,6 +6,8 @@ import ( "github.com/appwrite/sdk-for-go/client" "github.com/appwrite/sdk-for-go/models" "github.com/appwrite/sdk-for-go/file" + "net/url" + "fmt" "strings" ) @@ -825,6 +827,29 @@ func (srv *Storage) GetFileDownload(BucketId string, FileId string, optionalSett return &parsed, nil } +// GetFileDownloadURL get a file content by its unique ID. The endpoint +// response return with a 'Content-Disposition: attachment' header that tells +// the browser to start downloading the file to user downloads directory. +// Returns the URL for the resource instead of the content. +func (srv *Storage) GetFileDownloadURL(BucketId string, FileId string, optionalSetters ...GetFileDownloadOption) (*string, error) { + r := strings.NewReplacer("{bucketId}", BucketId, "{fileId}", FileId) + path := r.Replace("/storage/buckets/{bucketId}/files/{fileId}/download") + options := GetFileDownloadOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Token"] { + q.Set("token", fmt.Sprintf("%v", options.Token)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetFilePreviewOptions struct { Width int Height int @@ -1008,6 +1033,64 @@ func (srv *Storage) GetFilePreview(BucketId string, FileId string, optionalSette return &parsed, nil } +// GetFilePreviewURL get a file preview image. Currently, this method supports +// preview for image files (jpg, png, and gif), other supported formats, like +// pdf, docs, slides, and spreadsheets, will return the file icon image. You +// can also pass query string arguments for cutting and resizing your preview +// image. Preview is supported only for image files smaller than 10MB. +// Returns the URL for the resource instead of the content. +func (srv *Storage) GetFilePreviewURL(BucketId string, FileId string, optionalSetters ...GetFilePreviewOption) (*string, error) { + r := strings.NewReplacer("{bucketId}", BucketId, "{fileId}", FileId) + path := r.Replace("/storage/buckets/{bucketId}/files/{fileId}/preview") + options := GetFilePreviewOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Width"] { + q.Set("width", fmt.Sprintf("%v", options.Width)) + } + if options.enabledSetters["Height"] { + q.Set("height", fmt.Sprintf("%v", options.Height)) + } + if options.enabledSetters["Gravity"] { + q.Set("gravity", fmt.Sprintf("%v", options.Gravity)) + } + if options.enabledSetters["Quality"] { + q.Set("quality", fmt.Sprintf("%v", options.Quality)) + } + if options.enabledSetters["BorderWidth"] { + q.Set("borderWidth", fmt.Sprintf("%v", options.BorderWidth)) + } + if options.enabledSetters["BorderColor"] { + q.Set("borderColor", fmt.Sprintf("%v", options.BorderColor)) + } + if options.enabledSetters["BorderRadius"] { + q.Set("borderRadius", fmt.Sprintf("%v", options.BorderRadius)) + } + if options.enabledSetters["Opacity"] { + q.Set("opacity", fmt.Sprintf("%v", options.Opacity)) + } + if options.enabledSetters["Rotation"] { + q.Set("rotation", fmt.Sprintf("%v", options.Rotation)) + } + if options.enabledSetters["Background"] { + q.Set("background", fmt.Sprintf("%v", options.Background)) + } + if options.enabledSetters["Output"] { + q.Set("output", fmt.Sprintf("%v", options.Output)) + } + if options.enabledSetters["Token"] { + q.Set("token", fmt.Sprintf("%v", options.Token)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} type GetFileViewOptions struct { Token string enabledSetters map[string]bool @@ -1068,3 +1151,26 @@ func (srv *Storage) GetFileView(BucketId string, FileId string, optionalSetters return &parsed, nil } +// GetFileViewURL get a file content by its unique ID. This endpoint is +// similar to the download method but returns with no 'Content-Disposition: +// attachment' header. +// Returns the URL for the resource instead of the content. +func (srv *Storage) GetFileViewURL(BucketId string, FileId string, optionalSetters ...GetFileViewOption) (*string, error) { + r := strings.NewReplacer("{bucketId}", BucketId, "{fileId}", FileId) + path := r.Replace("/storage/buckets/{bucketId}/files/{fileId}/view") + options := GetFileViewOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + u, err := url.Parse(srv.client.Endpoint + path) + if err != nil { + return nil, err + } + q := u.Query() + if options.enabledSetters["Token"] { + q.Set("token", fmt.Sprintf("%v", options.Token)) + } + u.RawQuery = q.Encode() + result := u.String() + return &result, nil +} diff --git a/users/users.go b/users/users.go index d1535383..a15070df 100644 --- a/users/users.go +++ b/users/users.go @@ -871,6 +871,46 @@ func (srv *Users) UpdateEmail(UserId string, Email string)(*models.User, error) } return &parsed, nil +} + +// UpdateImpersonator enable or disable whether a user can impersonate other +// users. When impersonation headers are used, the request runs as the target +// user for API behavior, while internal audit logs still attribute the action +// to the original impersonator and store the impersonated target details only +// in internal audit payload data. +func (srv *Users) UpdateImpersonator(UserId string, Impersonator bool)(*models.User, error) { + r := strings.NewReplacer("{userId}", UserId) + path := r.Replace("/users/{userId}/impersonator") + params := map[string]interface{}{} + params["userId"] = UserId + params["impersonator"] = Impersonator + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("PATCH", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.User{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.User + parsed, ok := resp.Result.(models.User) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + } type CreateJWTOptions struct { SessionId string diff --git a/webhooks/webhooks.go b/webhooks/webhooks.go new file mode 100644 index 00000000..d36bd35f --- /dev/null +++ b/webhooks/webhooks.go @@ -0,0 +1,387 @@ +package webhooks + +import ( + "encoding/json" + "errors" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/models" + "strings" +) + +// Webhooks service +type Webhooks struct { + client client.Client +} + +func New(clt client.Client) *Webhooks { + return &Webhooks{ + client: clt, + } +} + +type ListOptions struct { + Queries []string + Total bool + enabledSetters map[string]bool +} +func (options ListOptions) New() *ListOptions { + options.enabledSetters = map[string]bool{ + "Queries": false, + "Total": false, + } + return &options +} +type ListOption func(*ListOptions) +func (srv *Webhooks) WithListQueries(v []string) ListOption { + return func(o *ListOptions) { + o.Queries = v + o.enabledSetters["Queries"] = true + } +} +func (srv *Webhooks) WithListTotal(v bool) ListOption { + return func(o *ListOptions) { + o.Total = v + o.enabledSetters["Total"] = true + } +} + +// List get a list of all webhooks belonging to the project. You can use the +// query params to filter your results. +func (srv *Webhooks) List(optionalSetters ...ListOption)(*models.WebhookList, error) { + path := "/webhooks" + options := ListOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + params := map[string]interface{}{} + if options.enabledSetters["Queries"] { + params["queries"] = options.Queries + } + if options.enabledSetters["Total"] { + params["total"] = options.Total + } + headers := map[string]interface{}{ + } + + resp, err := srv.client.Call("GET", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.WebhookList{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.WebhookList + parsed, ok := resp.Result.(models.WebhookList) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} +type CreateOptions struct { + Enabled bool + Security bool + HttpUser string + HttpPass string + enabledSetters map[string]bool +} +func (options CreateOptions) New() *CreateOptions { + options.enabledSetters = map[string]bool{ + "Enabled": false, + "Security": false, + "HttpUser": false, + "HttpPass": false, + } + return &options +} +type CreateOption func(*CreateOptions) +func (srv *Webhooks) WithCreateEnabled(v bool) CreateOption { + return func(o *CreateOptions) { + o.Enabled = v + o.enabledSetters["Enabled"] = true + } +} +func (srv *Webhooks) WithCreateSecurity(v bool) CreateOption { + return func(o *CreateOptions) { + o.Security = v + o.enabledSetters["Security"] = true + } +} +func (srv *Webhooks) WithCreateHttpUser(v string) CreateOption { + return func(o *CreateOptions) { + o.HttpUser = v + o.enabledSetters["HttpUser"] = true + } +} +func (srv *Webhooks) WithCreateHttpPass(v string) CreateOption { + return func(o *CreateOptions) { + o.HttpPass = v + o.enabledSetters["HttpPass"] = true + } +} + +// Create create a new webhook. Use this endpoint to configure a URL that will +// receive events from Appwrite when specific events occur. +func (srv *Webhooks) Create(WebhookId string, Url string, Name string, Events []string, optionalSetters ...CreateOption)(*models.Webhook, error) { + path := "/webhooks" + options := CreateOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + params := map[string]interface{}{} + params["webhookId"] = WebhookId + params["url"] = Url + params["name"] = Name + params["events"] = Events + if options.enabledSetters["Enabled"] { + params["enabled"] = options.Enabled + } + if options.enabledSetters["Security"] { + params["security"] = options.Security + } + if options.enabledSetters["HttpUser"] { + params["httpUser"] = options.HttpUser + } + if options.enabledSetters["HttpPass"] { + params["httpPass"] = options.HttpPass + } + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("POST", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Webhook{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Webhook + parsed, ok := resp.Result.(models.Webhook) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} + +// Get get a webhook by its unique ID. This endpoint returns details about a +// specific webhook configured for a project. +func (srv *Webhooks) Get(WebhookId string)(*models.Webhook, error) { + r := strings.NewReplacer("{webhookId}", WebhookId) + path := r.Replace("/webhooks/{webhookId}") + params := map[string]interface{}{} + params["webhookId"] = WebhookId + headers := map[string]interface{}{ + } + + resp, err := srv.client.Call("GET", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Webhook{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Webhook + parsed, ok := resp.Result.(models.Webhook) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} +type UpdateOptions struct { + Enabled bool + Security bool + HttpUser string + HttpPass string + enabledSetters map[string]bool +} +func (options UpdateOptions) New() *UpdateOptions { + options.enabledSetters = map[string]bool{ + "Enabled": false, + "Security": false, + "HttpUser": false, + "HttpPass": false, + } + return &options +} +type UpdateOption func(*UpdateOptions) +func (srv *Webhooks) WithUpdateEnabled(v bool) UpdateOption { + return func(o *UpdateOptions) { + o.Enabled = v + o.enabledSetters["Enabled"] = true + } +} +func (srv *Webhooks) WithUpdateSecurity(v bool) UpdateOption { + return func(o *UpdateOptions) { + o.Security = v + o.enabledSetters["Security"] = true + } +} +func (srv *Webhooks) WithUpdateHttpUser(v string) UpdateOption { + return func(o *UpdateOptions) { + o.HttpUser = v + o.enabledSetters["HttpUser"] = true + } +} +func (srv *Webhooks) WithUpdateHttpPass(v string) UpdateOption { + return func(o *UpdateOptions) { + o.HttpPass = v + o.enabledSetters["HttpPass"] = true + } +} + +// Update update a webhook by its unique ID. Use this endpoint to update the +// URL, events, or status of an existing webhook. +func (srv *Webhooks) Update(WebhookId string, Name string, Url string, Events []string, optionalSetters ...UpdateOption)(*models.Webhook, error) { + r := strings.NewReplacer("{webhookId}", WebhookId) + path := r.Replace("/webhooks/{webhookId}") + options := UpdateOptions{}.New() + for _, opt := range optionalSetters { + opt(options) + } + params := map[string]interface{}{} + params["webhookId"] = WebhookId + params["name"] = Name + params["url"] = Url + params["events"] = Events + if options.enabledSetters["Enabled"] { + params["enabled"] = options.Enabled + } + if options.enabledSetters["Security"] { + params["security"] = options.Security + } + if options.enabledSetters["HttpUser"] { + params["httpUser"] = options.HttpUser + } + if options.enabledSetters["HttpPass"] { + params["httpPass"] = options.HttpPass + } + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("PUT", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Webhook{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Webhook + parsed, ok := resp.Result.(models.Webhook) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} + +// Delete delete a webhook by its unique ID. Once deleted, the webhook will no +// longer receive project events. +func (srv *Webhooks) Delete(WebhookId string)(*interface{}, error) { + r := strings.NewReplacer("{webhookId}", WebhookId) + path := r.Replace("/webhooks/{webhookId}") + params := map[string]interface{}{} + params["webhookId"] = WebhookId + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("DELETE", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + var parsed interface{} + + err = json.Unmarshal(bytes, &parsed) + if err != nil { + return nil, err + } + return &parsed, nil + } + var parsed interface{} + parsed, ok := resp.Result.(interface{}) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +} + +// UpdateSignature update the webhook signature key. This endpoint can be used +// to regenerate the signature key used to sign and validate payload +// deliveries for a specific webhook. +func (srv *Webhooks) UpdateSignature(WebhookId string)(*models.Webhook, error) { + r := strings.NewReplacer("{webhookId}", WebhookId) + path := r.Replace("/webhooks/{webhookId}/signature") + params := map[string]interface{}{} + params["webhookId"] = WebhookId + headers := map[string]interface{}{ + "content-type": "application/json", + } + + resp, err := srv.client.Call("PATCH", path, headers, params) + if err != nil { + return nil, err + } + if strings.HasPrefix(resp.Type, "application/json") { + bytes := []byte(resp.Result.(string)) + + parsed := models.Webhook{}.New(bytes) + + err = json.Unmarshal(bytes, parsed) + if err != nil { + return nil, err + } + + return parsed, nil + } + var parsed models.Webhook + parsed, ok := resp.Result.(models.Webhook) + if !ok { + return nil, errors.New("unexpected response type") + } + return &parsed, nil + +}