From 1c7cb37efe9d1512ea338f0e9948649ccf63611c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 07:18:02 +0300 Subject: [PATCH 01/22] Added a new team page --- app/controllers/web/console.php | 18 +++++++++++++++--- app/views/console/users/index.phtml | 2 +- .../console/users/{view.phtml => user.phtml} | 6 +++--- public/scripts/routes.js | 18 ++++++++++++++---- 4 files changed, 33 insertions(+), 11 deletions(-) rename app/views/console/users/{view.phtml => user.phtml} (98%) diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index 480c4ff9ba..fcf4837356 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -277,14 +277,26 @@ $utopia->get('/console/users') ->setParam('body', $page); }); -$utopia->get('/console/users/view') +$utopia->get('/console/users/user') ->desc('Platform console project user') ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { - $page = new View(__DIR__.'/../../views/console/users/view.phtml'); + $page = new View(__DIR__.'/../../views/console/users/user.phtml'); $layout - ->setParam('title', APP_NAME.' - View User') + ->setParam('title', APP_NAME.' - User') + ->setParam('body', $page); + }); + +$utopia->get('/console/users/team') + ->desc('Platform console project team') + ->label('permission', 'public') + ->label('scope', 'console') + ->action(function () use ($layout) { + $page = new View(__DIR__.'/../../views/console/users/team.phtml'); + + $layout + ->setParam('title', APP_NAME.' - Team') ->setParam('body', $page); }); diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index f4b6282bc5..1968016c59 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -107,7 +107,7 @@ $providers = $this->getParam('providers', []); User Avatar - + ----- diff --git a/app/views/console/users/view.phtml b/app/views/console/users/user.phtml similarity index 98% rename from app/views/console/users/view.phtml rename to app/views/console/users/user.phtml index 8089fde0cf..18ca821343 100644 --- a/app/views/console/users/view.phtml +++ b/app/views/console/users/user.phtml @@ -30,7 +30,7 @@
-
  • +
  • Devices

  • -
  • +
  • Activity

    Date: Sun, 7 Jun 2020 07:18:19 +0300 Subject: [PATCH 02/22] New team page routes --- public/dist/scripts/app-all.js | 2 +- public/dist/scripts/app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index 8acc3d90d4..a6cf4fb169 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -2532,7 +2532,7 @@ return slf.renderToken(tokens,idx,opts);} md.renderer.rules.strong_open=renderEm;md.renderer.rules.strong_close=renderEm;return md;},true);})(window);(function(window){"use strict";window.ls.container.set('rtl',function(){var rtlStock="^ا^ب^ت^ث^ج^ح^خ^د^ذ^ر^ز^س^ش^ص^ض^ط^ظ^ع^غ^ف^ق^ك^ل^م^ن^ه^و^ي^א^ב^ג^ד^ה^ו^ז^ח^ט^י^כ^ך^ל^מ^ם^נ^ן^ס^ע^פ^ף^צ^ץ^ק^ר^ש^ת^";var special=["\n"," "," ","״",'"',"_","'","!","@","#","$","^","&","%","*","(",")","+","=","-","[","]","\\","/","{","}","|",":","<",">","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;iUnknown + +
    + + + +
    +
      +
    • +

      General

      + + + +
      +
      + + +
      +
      + User Avatar + +
      +
      + + Verified + + + Unverified + +
      +
      +
      +
      + +

      Members

      + + +
      +
      + +
      + +
      + +
        +
      • +
      + +
      +
      + + +
      +
      + +
      +
      + + +
      +
      +
      +
      +
    • +
    • +

      Devices

      + +
      + + + +
      +
      +
        +
      • +
        + + + + +
        + + + + on + +
        + + / +
        +
      • +
      +
      + +
      + + +
      +
      +
      + +
    • +
    • +

      Activity

      + +
      + + + + +
      +
    • +
    +
    + \ No newline at end of file From 9083ea0cdca94082797df7e979cb418f45d7fe7b Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 08:57:04 +0300 Subject: [PATCH 04/22] Updated routes --- app/controllers/web/console.php | 2 +- app/views/console/users/index.phtml | 31 ++--------------------------- public/dist/scripts/app-all.js | 2 +- public/dist/scripts/app.js | 2 +- public/scripts/routes.js | 8 ++++---- 5 files changed, 9 insertions(+), 36 deletions(-) diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index fcf4837356..d90966ba72 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -289,7 +289,7 @@ $utopia->get('/console/users/user') ->setParam('body', $page); }); -$utopia->get('/console/users/team') +$utopia->get('/console/users/teams/team') ->desc('Platform console project team') ->label('permission', 'public') ->label('scope', 'console') diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index 1968016c59..993d4f967b 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -253,36 +253,9 @@ $providers = $this->getParam('providers', []); Collection Avatar - + + diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index a6cf4fb169..3f80fda243 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -2532,7 +2532,7 @@ return slf.renderToken(tokens,idx,opts);} md.renderer.rules.strong_open=renderEm;md.renderer.rules.strong_close=renderEm;return md;},true);})(window);(function(window){"use strict";window.ls.container.set('rtl',function(){var rtlStock="^ا^ب^ت^ث^ج^ح^خ^د^ذ^ر^ز^س^ش^ص^ض^ط^ظ^ع^غ^ف^ق^ك^ل^م^ن^ه^و^ي^א^ב^ג^ד^ה^ו^ז^ח^ט^י^כ^ך^ל^מ^ם^נ^ן^ס^ע^פ^ף^צ^ץ^ק^ר^ש^ת^";var special=["\n"," "," ","״",'"',"_","'","!","@","#","$","^","&","%","*","(",")","+","=","-","[","]","\\","/","{","}","|",":","<",">","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i @@ -468,10 +468,10 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false); data-event="submit" data-loading="Sending invitation, please wait..." data-success="alert,trigger,reset" - data-success-param-alert-text="Invitation Sent Successfully" + data-success-param-alert-text="Invitation sent successfully" data-success-param-trigger-events="teams.createMembership" data-failure="alert" - data-failure-param-alert-text="Failed to Send Invite" + data-failure-param-alert-text="Failed to send invite" data-failure-param-alert-classname="error"> diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 15c1b658ed..c10fdad433 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -33,10 +33,6 @@
  • General

    - -
    @@ -72,24 +68,22 @@
  • -
    -
    + - -
    -
    + +
    diff --git a/app/views/console/users/user.phtml b/app/views/console/users/user.phtml index 18ca821343..d256c4e2b4 100644 --- a/app/views/console/users/user.phtml +++ b/app/views/console/users/user.phtml @@ -113,10 +113,10 @@ data-event="submit" data-param-user-id="{{router.params.id}}" data-success="alert,trigger" - data-success-param-alert-text="Blocked User Successfully" + data-success-param-alert-text="Blocked user successfully" data-success-param-trigger-events="users.update" data-failure="alert" - data-failure-param-alert-text="Failed to Block User" + data-failure-param-alert-text="Failed to block user" data-failure-param-alert-classname="error"> @@ -132,10 +132,10 @@ data-event="submit" data-param-user-id="{{router.params.id}}" data-success="alert,trigger" - data-success-param-alert-text="Activated User Successfully" + data-success-param-alert-text="Activated user successfully" data-success-param-trigger-events="users.update" data-failure="alert" - data-failure-param-alert-text="Failed to Activate User" + data-failure-param-alert-text="Failed to activate user" data-failure-param-alert-classname="error"> diff --git a/app/views/home/auth/join.phtml b/app/views/home/auth/join.phtml index 5996ff77b5..e5c0f6e72d 100644 --- a/app/views/home/auth/join.phtml +++ b/app/views/home/auth/join.phtml @@ -12,7 +12,7 @@ data-param-secret="{{router.params.secret}}" data-success="redirect,alert,trigger" data-success-param-redirect-url="/console?project={{router.params.project}}" - data-success-param-alert-text="Joined Team Successfully" + data-success-param-alert-text="Joined team successfully" data-success-param-trigger-events="teams.updateMembershipStatus" data-failure="redirect,alert" data-success-param-redirect-url="/console" From 2afb5776c01c177f670f933991a25f6843b57d12 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 10:48:06 +0300 Subject: [PATCH 06/22] Added option to update team name --- app/views/console/users/index.phtml | 4 +- app/views/console/users/team.phtml | 171 +++++----------------------- 2 files changed, 28 insertions(+), 147 deletions(-) diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index 993d4f967b..c3ae2ee3e4 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -253,9 +253,7 @@ $providers = $this->getParam('providers', []); Collection Avatar - - - + diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index c10fdad433..285c8957f1 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -30,28 +30,37 @@
      -
    • +
    • General

      - -
      + +
      -
      - User Avatar + -
      -
      - - Verified - - - Unverified - -
      -
      -
      + + + + + +
      + + +

      Members

      @@ -66,6 +75,7 @@
      • +
      • Created:
      Delete Team
      - -
      -
      - - -
      -
      -
      -
      -
    • -
    • -

      Devices

      - -
      - - - -
      -
      -
        -
      • -
        - - - - -
        - - - - on - -
        - - / -
        -
      • -
      -
      - -
      - - -
      -
      -
      - -
    • -
    • -

      Activity

      - -
      - - - -
    • +
    \ No newline at end of file From 950a66f294884d5226ca8b053288cc4f4320cab8 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 11:09:05 +0300 Subject: [PATCH 07/22] #380 added option to delete team from the console --- app/views/console/users/team.phtml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 285c8957f1..23140221ce 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -81,13 +81,15 @@
    From fb2663745d47ec59cf6144fbfda67162edaf5c2a Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 12:29:51 +0300 Subject: [PATCH 08/22] Updated Team UI --- CHANGES.md | 5 +- app/controllers/api/teams.php | 23 ++++---- app/views/console/settings/index.phtml | 2 +- app/views/console/users/team.phtml | 74 ++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6fcb7b9cdb..5ea597b6af 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,8 +2,11 @@ ## Features -- New route in Locale API to fetch a list of languages +- Added a new route in Locale API to fetch a list of languages - Added Google Fonts to Appwrite for offline availability +- Added option to delete team from the console +- Added option to view team members from the console +- Added option to join a user to any team from the console ## Bug Fixes diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index fad09b695e..89f1ff0df5 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -371,8 +371,12 @@ $utopia->get('/v1/teams/:teamId/memberships') ->label('sdk.method', 'getMemberships') ->label('sdk.description', '/docs/references/teams/get-team-members.md') ->param('teamId', '', function () { return new UID(); }, 'Team unique ID.') + ->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true) + ->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) + ->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true) ->action( - function ($teamId) use ($response, $projectDB) { + function ($teamId, $search, $limit, $offset, $orderType) use ($response, $projectDB) { $team = $projectDB->getDocument($teamId); if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { @@ -380,8 +384,12 @@ $utopia->get('/v1/teams/:teamId/memberships') } $memberships = $projectDB->getCollection([ - 'limit' => 50, - 'offset' => 0, + 'limit' => $limit, + 'offset' => $offset, + 'orderField' => 'joined', + 'orderType' => $orderType, + 'orderCast' => 'int', + 'search' => $search, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS, 'teamId='.$teamId, @@ -408,15 +416,8 @@ $utopia->get('/v1/teams/:teamId/memberships') ])); } - usort($users, function ($a, $b) { - if ($a['joined'] === 0 || $b['joined'] === 0) { - return $b['joined'] - $a['joined']; - } + $response->json(['sum' => $projectDB->getSum(), 'memberships' => $users]); - return $a['joined'] - $b['joined']; - }); - - $response->json($users); } ); diff --git a/app/views/console/settings/index.phtml b/app/views/console/settings/index.phtml index 34ac7bcca8..a52c74fd42 100644 --- a/app/views/console/settings/index.phtml +++ b/app/views/console/settings/index.phtml @@ -383,7 +383,7 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false); data-success-param-trigger-events="teams.getMemberships">
    -
      +
      • Members +
        +
        +

        No Memberships Found

        + +

        Create your first team member to get started

        +
        + +
        +
        results found
        + +
        + + + + + + + + + + + + + + + + + +
        NameMembersCreated
        + Collection Avatar + + +
        +
        +
        + +
        + + + + + + +
        + +
        +
        +
    From 0e6f36d78de295f41f96f40adf3e7b5eae6a8da0 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 15:29:12 +0300 Subject: [PATCH 09/22] Added invite form --- app/views/console/users/team.phtml | 34 +++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 45d98ebdd8..c31afd222f 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -110,7 +110,39 @@
    -
    + + +
    Date: Mon, 8 Jun 2020 07:38:39 +0300 Subject: [PATCH 10/22] Updated Console SDK --- app/sdks/client-web/README.md | 2 +- .../examples/account/create-o-auth2session.md | 2 +- app/sdks/client-web/src/sdk.js | 45 +- app/sdks/client-web/src/sdk.min.js | 8 +- app/sdks/client-web/types/index.d.ts | 29 +- app/sdks/console-web/README.md | 2 +- .../examples/account/create-o-auth2session.md | 2 +- .../docs/examples/projects/update-o-auth2.md | 2 +- app/sdks/console-web/src/sdk.js | 45 +- app/sdks/console-web/src/sdk.min.js | 8 +- app/sdks/console-web/types/index.d.ts | 29 +- public/dist/scripts/app-all.js | 39 +- public/dist/scripts/app-dep.js | 36 +- public/dist/scripts/app.js | 3 +- public/scripts/dependencies/appwrite.js | 490 ++++++++++++++---- 15 files changed, 546 insertions(+), 196 deletions(-) diff --git a/app/sdks/client-web/README.md b/app/sdks/client-web/README.md index e59480b4a9..093783ab41 100644 --- a/app/sdks/client-web/README.md +++ b/app/sdks/client-web/README.md @@ -1,7 +1,7 @@ # Appwrite Web SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-js.svg?v=1) -![Version](https://img.shields.io/badge/api%20version-0.6.1-blue.svg?v=1) +![Version](https://img.shields.io/badge/api%20version-0.6.2-blue.svg?v=1) Appwrite is an open-source backend as a service server that abstract and simplify 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 Web SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. diff --git a/app/sdks/client-web/docs/examples/account/create-o-auth2session.md b/app/sdks/client-web/docs/examples/account/create-o-auth2session.md index 5cc825a273..0c7430741c 100644 --- a/app/sdks/client-web/docs/examples/account/create-o-auth2session.md +++ b/app/sdks/client-web/docs/examples/account/create-o-auth2session.md @@ -5,7 +5,7 @@ sdk .setProject('5df5acd0d48c2') // Your project ID ; -let promise = sdk.account.createOAuth2Session('bitbucket'); +let promise = sdk.account.createOAuth2Session('amazon'); promise.then(function (response) { console.log(response); // Success diff --git a/app/sdks/client-web/src/sdk.js b/app/sdks/client-web/src/sdk.js index 0d7a7deaab..a423ae9cf9 100644 --- a/app/sdks/client-web/src/sdk.js +++ b/app/sdks/client-web/src/sdk.js @@ -276,10 +276,10 @@ * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -522,7 +522,7 @@ * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -563,7 +563,7 @@ * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -772,7 +772,7 @@ * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -1168,7 +1168,10 @@ /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -1942,10 +1945,14 @@ * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships: function(teamId) { + getMemberships: function(teamId, search = '', limit = 25, offset = 0, orderType = 'ASC') { if(teamId === undefined) { throw new Error('Missing required parameter: "teamId"'); } @@ -1954,6 +1961,22 @@ let payload = {}; + if(search) { + payload['search'] = search; + } + + if(limit) { + payload['limit'] = limit; + } + + if(offset) { + payload['offset'] = offset; + } + + if(orderType) { + payload['orderType'] = orderType; + } + return http .get(path, { 'content-type': 'application/json', @@ -1969,8 +1992,8 @@ * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/app/sdks/client-web/src/sdk.min.js b/app/sdks/client-web/src/sdk.min.js index 113a3402b8..bef842f31a 100644 --- a/app/sdks/client-web/src/sdk.min.js +++ b/app/sdks/client-web/src/sdk.min.js @@ -148,8 +148,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"')} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload.name=name} return http.put(path,{'content-type':'application/json',},payload)},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload.search=search} +if(limit){payload.limit=limit} +if(offset){payload.offset=offset} +if(orderType){payload.orderType=orderType} +return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} if(email===undefined){throw new Error('Missing required parameter: "email"')} if(roles===undefined){throw new Error('Missing required parameter: "roles"')} if(url===undefined){throw new Error('Missing required parameter: "url"')} diff --git a/app/sdks/client-web/types/index.d.ts b/app/sdks/client-web/types/index.d.ts index f2bc108bc4..2715af9f8d 100644 --- a/app/sdks/client-web/types/index.d.ts +++ b/app/sdks/client-web/types/index.d.ts @@ -64,10 +64,10 @@ declare namespace Appwrite { * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -170,7 +170,7 @@ declare namespace Appwrite { * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -186,7 +186,7 @@ declare namespace Appwrite { * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -276,7 +276,7 @@ declare namespace Appwrite { * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -431,7 +431,10 @@ declare namespace Appwrite { /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -758,10 +761,14 @@ declare namespace Appwrite { * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships(teamId: string): Promise; + getMemberships(teamId: string, search: string, limit: number, offset: number, orderType: string): Promise; /** * Create Team Membership @@ -772,8 +779,8 @@ declare namespace Appwrite { * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/app/sdks/console-web/README.md b/app/sdks/console-web/README.md index 8d44e2769b..68b7e8ff9c 100644 --- a/app/sdks/console-web/README.md +++ b/app/sdks/console-web/README.md @@ -1,7 +1,7 @@ # Appwrite Console SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-console.svg?v=1) -![Version](https://img.shields.io/badge/api%20version-0.6.1-blue.svg?v=1) +![Version](https://img.shields.io/badge/api%20version-0.6.2-blue.svg?v=1) Appwrite is an open-source backend as a service server that abstract and simplify 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 Console SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. diff --git a/app/sdks/console-web/docs/examples/account/create-o-auth2session.md b/app/sdks/console-web/docs/examples/account/create-o-auth2session.md index bea25a368f..4a3523693f 100644 --- a/app/sdks/console-web/docs/examples/account/create-o-auth2session.md +++ b/app/sdks/console-web/docs/examples/account/create-o-auth2session.md @@ -6,7 +6,7 @@ sdk .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key ; -let promise = sdk.account.createOAuth2Session('bitbucket'); +let promise = sdk.account.createOAuth2Session('amazon'); promise.then(function (response) { console.log(response); // Success diff --git a/app/sdks/console-web/docs/examples/projects/update-o-auth2.md b/app/sdks/console-web/docs/examples/projects/update-o-auth2.md index 4a82548a6a..479c5e9d30 100644 --- a/app/sdks/console-web/docs/examples/projects/update-o-auth2.md +++ b/app/sdks/console-web/docs/examples/projects/update-o-auth2.md @@ -6,7 +6,7 @@ sdk .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key ; -let promise = sdk.projects.updateOAuth2('[PROJECT_ID]', 'bitbucket'); +let promise = sdk.projects.updateOAuth2('[PROJECT_ID]', 'amazon'); promise.then(function (response) { console.log(response); // Success diff --git a/app/sdks/console-web/src/sdk.js b/app/sdks/console-web/src/sdk.js index 86e219cde5..08f0501f23 100644 --- a/app/sdks/console-web/src/sdk.js +++ b/app/sdks/console-web/src/sdk.js @@ -312,10 +312,10 @@ * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -558,7 +558,7 @@ * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -599,7 +599,7 @@ * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -810,7 +810,7 @@ * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -1421,7 +1421,10 @@ /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -3753,10 +3756,14 @@ * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships: function(teamId) { + getMemberships: function(teamId, search = '', limit = 25, offset = 0, orderType = 'ASC') { if(teamId === undefined) { throw new Error('Missing required parameter: "teamId"'); } @@ -3765,6 +3772,22 @@ let payload = {}; + if(search) { + payload['search'] = search; + } + + if(limit) { + payload['limit'] = limit; + } + + if(offset) { + payload['offset'] = offset; + } + + if(orderType) { + payload['orderType'] = orderType; + } + return http .get(path, { 'content-type': 'application/json', @@ -3780,8 +3803,8 @@ * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/app/sdks/console-web/src/sdk.min.js b/app/sdks/console-web/src/sdk.min.js index b43f612ff4..f0951f5030 100644 --- a/app/sdks/console-web/src/sdk.min.js +++ b/app/sdks/console-web/src/sdk.min.js @@ -319,8 +319,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"')} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload.name=name} return http.put(path,{'content-type':'application/json',},payload)},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload.search=search} +if(limit){payload.limit=limit} +if(offset){payload.offset=offset} +if(orderType){payload.orderType=orderType} +return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} if(email===undefined){throw new Error('Missing required parameter: "email"')} if(roles===undefined){throw new Error('Missing required parameter: "roles"')} if(url===undefined){throw new Error('Missing required parameter: "url"')} diff --git a/app/sdks/console-web/types/index.d.ts b/app/sdks/console-web/types/index.d.ts index 08f42c7cf4..65da150013 100644 --- a/app/sdks/console-web/types/index.d.ts +++ b/app/sdks/console-web/types/index.d.ts @@ -85,10 +85,10 @@ declare namespace Appwrite { * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -191,7 +191,7 @@ declare namespace Appwrite { * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -207,7 +207,7 @@ declare namespace Appwrite { * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -297,7 +297,7 @@ declare namespace Appwrite { * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -522,7 +522,10 @@ declare namespace Appwrite { /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -1402,10 +1405,14 @@ declare namespace Appwrite { * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships(teamId: string): Promise; + getMemberships(teamId: string, search: string, limit: number, offset: number, orderType: string): Promise; /** * Create Team Membership @@ -1416,8 +1423,8 @@ declare namespace Appwrite { * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index 3f80fda243..1293d35897 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -18,8 +18,7 @@ request.setRequestHeader(key,headers[key]);}} request.onload=function(){if(4===request.readyState&&399>=request.status){let data=request.response;let contentType=this.getResponseHeader('content-type')||'';contentType=contentType.substring(0,contentType.indexOf(';'));switch(contentType){case'application/json':data=JSON.parse(data);break;} let cookieFallback=this.getResponseHeader('X-Fallback-Cookies')||'';if(window.localStorage&&cookieFallback){window.console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');window.localStorage.setItem('cookieFallback',cookieFallback);} resolve(data);}else{reject(new Error(request.statusText));}};if(progress){request.addEventListener('progress',progress);request.upload.addEventListener('progress',progress,false);} -request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let iframe=function(method,url,params){let form=document.createElement('form');form.setAttribute('method',method);form.setAttribute('action',config.endpoint+url);for(let key in params){if(params.hasOwnProperty(key)){let hiddenField=document.createElement("input");hiddenField.setAttribute("type","hidden");hiddenField.setAttribute("name",key);hiddenField.setAttribute("value",params[key]);form.appendChild(hiddenField);}} -document.body.appendChild(form);return form.submit();};let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} +request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} @@ -52,12 +51,10 @@ return http.put(path,{'content-type':'application/json',},payload);},getSessions if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account/sessions';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} -return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success,failure){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} -if(success===undefined){throw new Error('Missing required parameter: "success"');} -if(failure===undefined){throw new Error('Missing required parameter: "failure"');} +return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success='https://appwrite.io/auth/oauth2/success',failure='https://appwrite.io/auth/oauth2/failure'){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} let path='/account/sessions/oauth2/{provider}'.replace(new RegExp('{provider}','g'),provider);let payload={};if(success){payload['success']=success;} if(failure){payload['failure']=failure;} -payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');window.location=config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} let path='/account/sessions/{sessionId}'.replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createVerification:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/account/verification';let payload={};if(url){payload['url']=url;} return http.post(path,{'content-type':'application/json',},payload);},updateVerification:function(userId,secret){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} @@ -68,26 +65,26 @@ return http.put(path,{'content-type':'application/json',},payload);}};let avatar let path='/avatars/browsers/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/credit-cards/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/favicon';let payload={};if(url){payload['url']=url;} -return http.get(path,{'content-type':'application/json',},payload);},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/flags/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/image';let payload={};if(url){payload['url']=url;} if(width){payload['width']=width;} if(height){payload['height']=height;} -return http.get(path,{'content-type':'application/json',},payload);},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} let path='/avatars/qr';let payload={};if(text){payload['text']=text;} if(size){payload['size']=size;} if(margin){payload['margin']=margin;} if(download){payload['download']=download;} -return http.get(path,{'content-type':'application/json',},payload);}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} if(limit){payload['limit']=limit;} if(offset){payload['offset']=offset;} if(orderType){payload['orderType']=orderType;} @@ -141,7 +138,8 @@ if(read){payload['read']=read;} if(write){payload['write']=write;} return http.patch(path,{'content-type':'application/json',},payload);},deleteDocument:function(collectionId,documentId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} if(documentId===undefined){throw new Error('Missing required parameter: "documentId"');} -let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} +let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getCollectionLogs:function(collectionId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} +let path='/database/collections/{collectionId}/logs'.replace(new RegExp('{collectionId}','g'),collectionId);let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} let path='/projects';let payload={};if(name){payload['name']=name;} if(teamId){payload['teamId']=teamId;} @@ -259,7 +257,7 @@ if(httpUser){payload['httpUser']=httpUser;} if(httpPass){payload['httpPass']=httpPass;} return http.put(path,{'content-type':'application/json',},payload);},deleteTask:function(projectId,taskId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} if(taskId===undefined){throw new Error('Missing required parameter: "taskId"');} -let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='monthly'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} +let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='last30'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/usage'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(range){payload['range']=range;} return http.get(path,{'content-type':'application/json',},payload);},listWebhooks:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/webhooks'.replace(new RegExp('{projectId}','g'),projectId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createWebhook:function(projectId,name,events,url,security,httpUser='',httpPass=''){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} @@ -327,8 +325,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"');} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload['name']=name;} return http.put(path,{'content-type':'application/json',},payload);},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload['search']=search;} +if(limit){payload['limit']=limit;} +if(offset){payload['offset']=offset;} +if(orderType){payload['orderType']=orderType;} +return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} if(email===undefined){throw new Error('Missing required parameter: "email"');} if(roles===undefined){throw new Error('Missing required parameter: "roles"');} if(url===undefined){throw new Error('Missing required parameter: "url"');} @@ -366,7 +368,7 @@ if(sessionId===undefined){throw new Error('Missing required parameter: "sessionI let path='/users/{userId}/sessions/{sessionId}'.replace(new RegExp('{userId}','g'),userId).replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},updateStatus:function(userId,status){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} if(status===undefined){throw new Error('Missing required parameter: "status"');} let path='/users/{userId}/status'.replace(new RegExp('{userId}','g'),userId);let payload={};if(status){payload['status']=status;} -return http.patch(path,{'content-type':'application/json',},payload);}};return{setEndpoint:setEndpoint,setProject:setProject,setKey:setKey,setLocale:setLocale,setMode:setMode,account:account,avatars:avatars,database:database,locale:locale,projects:projects,storage:storage,teams:teams,users:users};};if(typeof module!=="undefined"){module.exports=window.Appwrite;}})((typeof window!=="undefined")?window:{});(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart=f()}})(function(){var define,module,exports;return(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=50)?'...':'';return $value.substring(0,50)+postfix;;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} +return $value;}).add("platformsLimit",function($value){return $value;}).add("limit",function($value){let postfix=($value.length>=50)?'...':'';return $value.substring(0,50)+postfix;;}).add("arraySentence",function($value){if(!Array.isArray($value)){return'';} +return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";} return annotate(number,maxPlaces,forcePlaces,abbr);} function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;} diff --git a/public/dist/scripts/app-dep.js b/public/dist/scripts/app-dep.js index 22e19c4fae..f9d07fdc09 100644 --- a/public/dist/scripts/app-dep.js +++ b/public/dist/scripts/app-dep.js @@ -18,8 +18,7 @@ request.setRequestHeader(key,headers[key]);}} request.onload=function(){if(4===request.readyState&&399>=request.status){let data=request.response;let contentType=this.getResponseHeader('content-type')||'';contentType=contentType.substring(0,contentType.indexOf(';'));switch(contentType){case'application/json':data=JSON.parse(data);break;} let cookieFallback=this.getResponseHeader('X-Fallback-Cookies')||'';if(window.localStorage&&cookieFallback){window.console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');window.localStorage.setItem('cookieFallback',cookieFallback);} resolve(data);}else{reject(new Error(request.statusText));}};if(progress){request.addEventListener('progress',progress);request.upload.addEventListener('progress',progress,false);} -request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let iframe=function(method,url,params){let form=document.createElement('form');form.setAttribute('method',method);form.setAttribute('action',config.endpoint+url);for(let key in params){if(params.hasOwnProperty(key)){let hiddenField=document.createElement("input");hiddenField.setAttribute("type","hidden");hiddenField.setAttribute("name",key);hiddenField.setAttribute("value",params[key]);form.appendChild(hiddenField);}} -document.body.appendChild(form);return form.submit();};let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} +request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} @@ -52,12 +51,10 @@ return http.put(path,{'content-type':'application/json',},payload);},getSessions if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account/sessions';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} -return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success,failure){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} -if(success===undefined){throw new Error('Missing required parameter: "success"');} -if(failure===undefined){throw new Error('Missing required parameter: "failure"');} +return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success='https://appwrite.io/auth/oauth2/success',failure='https://appwrite.io/auth/oauth2/failure'){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} let path='/account/sessions/oauth2/{provider}'.replace(new RegExp('{provider}','g'),provider);let payload={};if(success){payload['success']=success;} if(failure){payload['failure']=failure;} -payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');window.location=config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} let path='/account/sessions/{sessionId}'.replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createVerification:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/account/verification';let payload={};if(url){payload['url']=url;} return http.post(path,{'content-type':'application/json',},payload);},updateVerification:function(userId,secret){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} @@ -68,26 +65,26 @@ return http.put(path,{'content-type':'application/json',},payload);}};let avatar let path='/avatars/browsers/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/credit-cards/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/favicon';let payload={};if(url){payload['url']=url;} -return http.get(path,{'content-type':'application/json',},payload);},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/flags/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/image';let payload={};if(url){payload['url']=url;} if(width){payload['width']=width;} if(height){payload['height']=height;} -return http.get(path,{'content-type':'application/json',},payload);},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} let path='/avatars/qr';let payload={};if(text){payload['text']=text;} if(size){payload['size']=size;} if(margin){payload['margin']=margin;} if(download){payload['download']=download;} -return http.get(path,{'content-type':'application/json',},payload);}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} if(limit){payload['limit']=limit;} if(offset){payload['offset']=offset;} if(orderType){payload['orderType']=orderType;} @@ -141,7 +138,8 @@ if(read){payload['read']=read;} if(write){payload['write']=write;} return http.patch(path,{'content-type':'application/json',},payload);},deleteDocument:function(collectionId,documentId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} if(documentId===undefined){throw new Error('Missing required parameter: "documentId"');} -let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} +let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getCollectionLogs:function(collectionId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} +let path='/database/collections/{collectionId}/logs'.replace(new RegExp('{collectionId}','g'),collectionId);let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} let path='/projects';let payload={};if(name){payload['name']=name;} if(teamId){payload['teamId']=teamId;} @@ -259,7 +257,7 @@ if(httpUser){payload['httpUser']=httpUser;} if(httpPass){payload['httpPass']=httpPass;} return http.put(path,{'content-type':'application/json',},payload);},deleteTask:function(projectId,taskId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} if(taskId===undefined){throw new Error('Missing required parameter: "taskId"');} -let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='monthly'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} +let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='last30'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/usage'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(range){payload['range']=range;} return http.get(path,{'content-type':'application/json',},payload);},listWebhooks:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/webhooks'.replace(new RegExp('{projectId}','g'),projectId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createWebhook:function(projectId,name,events,url,security,httpUser='',httpPass=''){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} @@ -327,8 +325,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"');} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload['name']=name;} return http.put(path,{'content-type':'application/json',},payload);},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload['search']=search;} +if(limit){payload['limit']=limit;} +if(offset){payload['offset']=offset;} +if(orderType){payload['orderType']=orderType;} +return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} if(email===undefined){throw new Error('Missing required parameter: "email"');} if(roles===undefined){throw new Error('Missing required parameter: "roles"');} if(url===undefined){throw new Error('Missing required parameter: "url"');} @@ -366,7 +368,7 @@ if(sessionId===undefined){throw new Error('Missing required parameter: "sessionI let path='/users/{userId}/sessions/{sessionId}'.replace(new RegExp('{userId}','g'),userId).replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},updateStatus:function(userId,status){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} if(status===undefined){throw new Error('Missing required parameter: "status"');} let path='/users/{userId}/status'.replace(new RegExp('{userId}','g'),userId);let payload={};if(status){payload['status']=status;} -return http.patch(path,{'content-type':'application/json',},payload);}};return{setEndpoint:setEndpoint,setProject:setProject,setKey:setKey,setLocale:setLocale,setMode:setMode,account:account,avatars:avatars,database:database,locale:locale,projects:projects,storage:storage,teams:teams,users:users};};if(typeof module!=="undefined"){module.exports=window.Appwrite;}})((typeof window!=="undefined")?window:{});(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart=f()}})(function(){var define,module,exports;return(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=50)?'...':'';return $value.substring(0,50)+postfix;;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} +return $value;}).add("platformsLimit",function($value){return $value;}).add("limit",function($value){let postfix=($value.length>=50)?'...':'';return $value.substring(0,50)+postfix;;}).add("arraySentence",function($value){if(!Array.isArray($value)){return'';} +return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";} return annotate(number,maxPlaces,forcePlaces,abbr);} function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;} diff --git a/public/scripts/dependencies/appwrite.js b/public/scripts/dependencies/appwrite.js index 590b45116f..08f0501f23 100644 --- a/public/scripts/dependencies/appwrite.js +++ b/public/scripts/dependencies/appwrite.js @@ -286,28 +286,6 @@ } }(window.document); - let iframe = function(method, url, params) { - let form = document.createElement('form'); - - form.setAttribute('method', method); - form.setAttribute('action', config.endpoint + url); - - for(let key in params) { - if(params.hasOwnProperty(key)) { - let hiddenField = document.createElement("input"); - hiddenField.setAttribute("type", "hidden"); - hiddenField.setAttribute("name", key); - hiddenField.setAttribute("value", params[key]); - - form.appendChild(hiddenField); - } - } - - document.body.appendChild(form); - - return form.submit(); - }; - let account = { /** @@ -334,10 +312,10 @@ * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -580,7 +558,7 @@ * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -621,7 +599,7 @@ * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -768,21 +746,13 @@ * @param {string} success * @param {string} failure * @throws {Error} - * @return {string} + * @return {Promise} */ - createOAuth2Session: function(provider, success, failure) { + createOAuth2Session: function(provider, success = 'https://appwrite.io/auth/oauth2/success', failure = 'https://appwrite.io/auth/oauth2/failure') { if(provider === undefined) { throw new Error('Missing required parameter: "provider"'); } - if(success === undefined) { - throw new Error('Missing required parameter: "success"'); - } - - if(failure === undefined) { - throw new Error('Missing required parameter: "failure"'); - } - let path = '/account/sessions/oauth2/{provider}'.replace(new RegExp('{provider}', 'g'), provider); let payload = {}; @@ -800,8 +770,8 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - - return config.endpoint + path + ((query) ? '?' + query : ''); + + window.location = config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -840,7 +810,7 @@ * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -926,7 +896,7 @@ * @param {number} height * @param {number} quality * @throws {Error} - * @return {Promise} + * @return {string} */ getBrowser: function(code, width = 100, height = 100, quality = 100) { if(code === undefined) { @@ -949,10 +919,13 @@ payload['quality'] = quality; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -968,7 +941,7 @@ * @param {number} height * @param {number} quality * @throws {Error} - * @return {Promise} + * @return {string} */ getCreditCard: function(code, width = 100, height = 100, quality = 100) { if(code === undefined) { @@ -991,10 +964,13 @@ payload['quality'] = quality; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1005,7 +981,7 @@ * * @param {string} url * @throws {Error} - * @return {Promise} + * @return {string} */ getFavicon: function(url) { if(url === undefined) { @@ -1020,10 +996,13 @@ payload['url'] = url; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1038,7 +1017,7 @@ * @param {number} height * @param {number} quality * @throws {Error} - * @return {Promise} + * @return {string} */ getFlag: function(code, width = 100, height = 100, quality = 100) { if(code === undefined) { @@ -1061,10 +1040,13 @@ payload['quality'] = quality; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1079,7 +1061,7 @@ * @param {number} width * @param {number} height * @throws {Error} - * @return {Promise} + * @return {string} */ getImage: function(url, width = 400, height = 400) { if(url === undefined) { @@ -1102,10 +1084,13 @@ payload['height'] = height; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1119,7 +1104,7 @@ * @param {number} margin * @param {number} download * @throws {Error} - * @return {Promise} + * @return {string} */ getQR: function(text, size = 400, margin = 1, download = 0) { if(text === undefined) { @@ -1146,10 +1131,13 @@ payload['download'] = download; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); } }; @@ -1203,9 +1191,9 @@ * Create a new Collection. * * @param {string} name - * @param {array} read - * @param {array} write - * @param {array} rules + * @param {string[]} read + * @param {string[]} write + * @param {string[]} rules * @throws {Error} * @return {Promise} */ @@ -1284,9 +1272,9 @@ * * @param {string} collectionId * @param {string} name - * @param {array} read - * @param {array} write - * @param {array} rules + * @param {string[]} read + * @param {string[]} write + * @param {string[]} rules * @throws {Error} * @return {Promise} */ @@ -1367,7 +1355,7 @@ * modes](/docs/admin). * * @param {string} collectionId - * @param {array} filters + * @param {string[]} filters * @param {number} offset * @param {number} limit * @param {string} orderField @@ -1433,12 +1421,15 @@ /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @param {string} parentDocument * @param {string} parentProperty * @param {string} parentPropertyType @@ -1533,8 +1524,8 @@ * @param {string} collectionId * @param {string} documentId * @param {object} data - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @throws {Error} * @return {Promise} */ @@ -1610,6 +1601,272 @@ .delete(path, { 'content-type': 'application/json', }, payload); + }, + + /** + * Get Collection Logs + * + * + * @param {string} collectionId + * @throws {Error} + * @return {Promise} + */ + getCollectionLogs: function(collectionId) { + if(collectionId === undefined) { + throw new Error('Missing required parameter: "collectionId"'); + } + + let path = '/database/collections/{collectionId}/logs'.replace(new RegExp('{collectionId}', 'g'), collectionId); + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + } + }; + + let health = { + + /** + * Get HTTP + * + * Check the Appwrite HTTP server is up and responsive. + * + * @throws {Error} + * @return {Promise} + */ + get: function() { + let path = '/health'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Anti virus + * + * Check the Appwrite Anti Virus server is up and connection is successful. + * + * @throws {Error} + * @return {Promise} + */ + getAntiVirus: function() { + let path = '/health/anti-virus'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Cache + * + * Check the Appwrite in-memory cache server is up and connection is + * successful. + * + * @throws {Error} + * @return {Promise} + */ + getCache: function() { + let path = '/health/cache'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get DB + * + * Check the Appwrite database server is up and connection is successful. + * + * @throws {Error} + * @return {Promise} + */ + getDB: function() { + let path = '/health/db'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Certificate Queue + * + * Get the number of certificates that are waiting to be issued against + * [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue + * server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueCertificates: function() { + let path = '/health/queue/certificates'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Functions Queue + * + * + * @throws {Error} + * @return {Promise} + */ + getQueueFunctions: function() { + let path = '/health/queue/functions'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Logs Queue + * + * Get the number of logs that are waiting to be processed in the Appwrite + * internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueLogs: function() { + let path = '/health/queue/logs'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Tasks Queue + * + * Get the number of tasks that are waiting to be processed in the Appwrite + * internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueTasks: function() { + let path = '/health/queue/tasks'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Usage Queue + * + * Get the number of usage stats that are waiting to be processed in the + * Appwrite internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueUsage: function() { + let path = '/health/queue/usage'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Webhooks Queue + * + * Get the number of webhooks that are waiting to be processed in the Appwrite + * internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueWebhooks: function() { + let path = '/health/queue/webhooks'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Local Storage + * + * Check the Appwrite local storage device is up and connection is successful. + * + * @throws {Error} + * @return {Promise} + */ + getStorageLocal: function() { + let path = '/health/storage/local'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Time + * + * Check the Appwrite server time is synced with Google remote NTP server. We + * use this technology to smoothly handle leap seconds with no disruptive + * events. The [Network Time + * Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol) (NTP) is + * used by hundreds of millions of computers and devices to synchronize their + * clocks over the Internet. If your computer sets its own clock, it likely + * uses NTP. + * + * @throws {Error} + * @return {Promise} + */ + getTime: function() { + let path = '/health/time'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); } }; @@ -1640,7 +1897,7 @@ }, /** - * List Countries + * List Continents * * List of all continents. You can use the locale header to get the data in a * supported language. @@ -2142,7 +2399,7 @@ * * @param {string} projectId * @param {string} name - * @param {array} scopes + * @param {string[]} scopes * @throws {Error} * @return {Promise} */ @@ -2212,7 +2469,7 @@ * @param {string} projectId * @param {string} keyId * @param {string} name - * @param {array} scopes + * @param {string[]} scopes * @throws {Error} * @return {Promise} */ @@ -2542,7 +2799,7 @@ * @param {number} security * @param {string} httpMethod * @param {string} httpUrl - * @param {array} httpHeaders + * @param {string[]} httpHeaders * @param {string} httpUser * @param {string} httpPass * @throws {Error} @@ -2663,7 +2920,7 @@ * @param {number} security * @param {string} httpMethod * @param {string} httpUrl - * @param {array} httpHeaders + * @param {string[]} httpHeaders * @param {string} httpUser * @param {string} httpPass * @throws {Error} @@ -2781,10 +3038,11 @@ * * * @param {string} projectId + * @param {string} range * @throws {Error} * @return {Promise} */ - getUsage: function(projectId, range = 'monthly') { + getUsage: function(projectId, range = 'last30') { if(projectId === undefined) { throw new Error('Missing required parameter: "projectId"'); } @@ -2832,7 +3090,7 @@ * * @param {string} projectId * @param {string} name - * @param {array} events + * @param {string[]} events * @param {string} url * @param {number} security * @param {string} httpUser @@ -2930,7 +3188,7 @@ * @param {string} projectId * @param {string} webhookId * @param {string} name - * @param {array} events + * @param {string[]} events * @param {string} url * @param {number} security * @param {string} httpUser @@ -3077,8 +3335,8 @@ * read and write arguments. * * @param {File} file - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @throws {Error} * @return {Promise} */ @@ -3149,8 +3407,8 @@ * to update this resource. * * @param {string} fileId - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @throws {Error} * @return {Promise} */ @@ -3235,7 +3493,7 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - + return config.endpoint + path + ((query) ? '?' + query : ''); }, @@ -3290,7 +3548,7 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - + return config.endpoint + path + ((query) ? '?' + query : ''); }, @@ -3323,7 +3581,7 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - + return config.endpoint + path + ((query) ? '?' + query : ''); } }; @@ -3380,7 +3638,7 @@ * project. * * @param {string} name - * @param {array} roles + * @param {string[]} roles * @throws {Error} * @return {Promise} */ @@ -3498,10 +3756,14 @@ * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships: function(teamId) { + getMemberships: function(teamId, search = '', limit = 25, offset = 0, orderType = 'ASC') { if(teamId === undefined) { throw new Error('Missing required parameter: "teamId"'); } @@ -3510,6 +3772,22 @@ let payload = {}; + if(search) { + payload['search'] = search; + } + + if(limit) { + payload['limit'] = limit; + } + + if(offset) { + payload['offset'] = offset; + } + + if(orderType) { + payload['orderType'] = orderType; + } + return http .get(path, { 'content-type': 'application/json', @@ -3525,8 +3803,8 @@ * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -3535,7 +3813,7 @@ * * @param {string} teamId * @param {string} email - * @param {array} roles + * @param {string[]} roles * @param {string} url * @param {string} name * @throws {Error} @@ -3922,10 +4200,7 @@ throw new Error('Missing required parameter: "sessionId"'); } - let path = '/users/{userId}/sessions/{sessionId}' - .replace(new RegExp('{userId}', 'g'), userId) - .replace(new RegExp('{sessionId}', 'g'), sessionId) - ; + let path = '/users/{userId}/sessions/{sessionId}'.replace(new RegExp('{userId}', 'g'), userId).replace(new RegExp('{sessionId}', 'g'), sessionId); let payload = {}; @@ -3978,6 +4253,7 @@ account: account, avatars: avatars, database: database, + health: health, locale: locale, projects: projects, storage: storage, From 591ff738ee309a0fa1ffbe3263e2411d0a292885 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 07:40:13 +0300 Subject: [PATCH 11/22] Added roles tooltip --- app/views/console/users/team.phtml | 123 +++++++++++++++++------------ public/scripts/filters.js | 7 ++ 2 files changed, 78 insertions(+), 52 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index c31afd222f..b6e54838a0 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -1,7 +1,7 @@
    @@ -34,7 +34,7 @@

    General

    -
    +
    @@ -67,13 +67,13 @@
    + data-name="project-members">

    No Memberships Found

    @@ -81,94 +81,113 @@

    Create your first team member to get started

    -
    -
    results found
    +
    +
    members found
    -
    - - - - - - - - - - - - - - - - - -
    NameMembersCreated
    - Collection Avatar - - -
    +
    +
      +
    • + + + + + + + + + User Avatar + +
      +    + + +
      +   Pending Approval +
    • +
    - diff --git a/public/scripts/filters.js b/public/scripts/filters.js index 6f08193df6..54d0fe8060 100644 --- a/public/scripts/filters.js +++ b/public/scripts/filters.js @@ -406,6 +406,13 @@ window.ls.filter return $value.substring(0, 50) + postfix; ; }) + .add("arraySentence", function($value) { + if(!Array.isArray($value)) { + return ''; + } + + return $value.join(", ").replace(/,\s([^,]+)$/, ' and $1'); + }) ; function abbreviate(number, maxPlaces, forcePlaces, forceLetter) { From 157b91b63b8949f6177d303eefe7995cad43fdb1 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 08:42:01 +0300 Subject: [PATCH 12/22] Fixed team member count --- CHANGES.md | 1 + app/controllers/api/teams.php | 8 +++++--- app/views/console/users/team.phtml | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5ea597b6af..5309635170 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ ## Bug Fixes - Fixed output of /v1/health/queue/certificates returning wrong data +- Fixed bug where team members count was wrong in some cases ## Security diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 89f1ff0df5..35b5be4c1b 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -584,9 +584,11 @@ $utopia->delete('/v1/teams/:teamId/memberships/:inviteId') throw new Exception('Failed to remove membership from DB', 500); } - $team = $projectDB->updateDocument(array_merge($team->getArrayCopy(), [ - 'sum' => $team->getAttribute('sum', 0) - 1, - ])); + if ($membership->getAttribute('confirm')) { // Count only confirmed members + $team = $projectDB->updateDocument(array_merge($team->getArrayCopy(), [ + 'sum' => $team->getAttribute('sum', 0) - 1, + ])); + } if (false === $team) { throw new Exception('Failed saving team to DB', 500); diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index b6e54838a0..1ce7f40ac4 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -82,7 +82,7 @@
    -
    members found
    +
    memberships found
      @@ -153,7 +153,7 @@
      - +  
      From 0060dfe7151b14dc7d357c3c48cde94d9ef37775 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 11:01:11 +0300 Subject: [PATCH 13/22] Fix for tests --- app/views/console/users/team.phtml | 4 ++-- tests/e2e/Services/Teams/TeamsBaseClient.php | 9 +++++---- tests/e2e/Services/Teams/TeamsBaseServer.php | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 1ce7f40ac4..d4050c9e77 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -75,10 +75,10 @@ data-scope="sdk" data-name="project-members"> -
      +

      No Memberships Found

      -

      Create your first team member to get started

      +

      Add your first team member to get started

      diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 0b91f862d5..05394a391c 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -22,10 +22,11 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertNotEmpty($response['body'][0]['$id']); - $this->assertEquals($this->getUser()['name'], $response['body'][0]['name']); - $this->assertEquals($this->getUser()['email'], $response['body'][0]['email']); - $this->assertEquals('owner', $response['body'][0]['roles'][0]); + $this->assertIsInt($response['body']['sum']); + $this->assertNotEmpty($response['body']['memberships'][0]['$id']); + $this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']); + $this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']); + $this->assertEquals('owner', $response['body'][0]['roles']['memberships'][0]); /** * Test for FAILURE diff --git a/tests/e2e/Services/Teams/TeamsBaseServer.php b/tests/e2e/Services/Teams/TeamsBaseServer.php index 6b00a65597..8de0f2ede8 100644 --- a/tests/e2e/Services/Teams/TeamsBaseServer.php +++ b/tests/e2e/Services/Teams/TeamsBaseServer.php @@ -22,7 +22,7 @@ trait TeamsBaseServer ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']); + $this->assertEquals(0, $response['body']['sum']); /** * Test for FAILURE From ee7f6ce9763caa0c361b29e99455658569e0129a Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 11:11:39 +0300 Subject: [PATCH 14/22] Test fix --- tests/e2e/Services/Teams/TeamsBaseClient.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 05394a391c..db9ecdf151 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -26,7 +26,7 @@ trait TeamsBaseClient $this->assertNotEmpty($response['body']['memberships'][0]['$id']); $this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']); $this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']); - $this->assertEquals('owner', $response['body'][0]['roles']['memberships'][0]); + $this->assertEquals('owner', $response['body'][0]['memberships']['roles'][0]); /** * Test for FAILURE @@ -234,6 +234,8 @@ trait TeamsBaseClient $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']); + var_dump($response); + return []; } } \ No newline at end of file From 38fae2bd874621aebcdd952d1e1a603a2e92ce4c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 11:23:03 +0300 Subject: [PATCH 15/22] Fixed test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index db9ecdf151..ec4676fe67 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -26,7 +26,7 @@ trait TeamsBaseClient $this->assertNotEmpty($response['body']['memberships'][0]['$id']); $this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']); $this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']); - $this->assertEquals('owner', $response['body'][0]['memberships']['roles'][0]); + $this->assertEquals('owner', $response['body']['memberships'][0]['roles'][0]); /** * Test for FAILURE From 4f62cdc6dee556790b270ed85da34071bbb223fc Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 12:03:08 +0300 Subject: [PATCH 16/22] Fixed test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index ec4676fe67..6d6df372a9 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -232,7 +232,7 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(1, $response['body']); + $this->assertCount(1, $response['body']['memberships']); var_dump($response); From 7d5ee934ee757ee4a7a16e0c029b5499b441229c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 19:15:13 +0300 Subject: [PATCH 17/22] Added link to user page --- app/views/console/users/team.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index d4050c9e77..435785ae52 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -103,13 +103,13 @@ - + User Avatar
      -    +   
      From 26a133a3f87c603cb12d32e5b8f7f4de86618dac Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 19:15:35 +0300 Subject: [PATCH 18/22] Allowed admin to auto-add new member to a team --- app/controllers/api/teams.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 35b5be4c1b..e235c3536a 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -215,7 +215,7 @@ $utopia->post('/v1/teams/:teamId/memberships') ->param('roles', [], function () { return new ArrayList(new Text(128)); }, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions).') ->param('url', '', function () use ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.') // TODO add our own built-in confirm page ->action( - function ($teamId, $email, $name, $roles, $url) use ($response, $register, $project, $user, $audit, $projectDB) { + function ($teamId, $email, $name, $roles, $url) use ($response, $register, $project, $user, $audit, $projectDB, $mode) { $name = (empty($name)) ? $email : $name; $team = $projectDB->getDocument($teamId); @@ -285,7 +285,7 @@ $utopia->post('/v1/teams/:teamId/memberships') } } - if (!$isOwner) { + if (!$isOwner && (APP_MODE_ADMIN !== $mode)) { throw new Exception('User is not allowed to send invitations for this team', 401); } @@ -302,11 +302,18 @@ $utopia->post('/v1/teams/:teamId/memberships') 'roles' => $roles, 'invited' => time(), 'joined' => 0, - 'confirm' => false, + 'confirm' => (APP_MODE_ADMIN === $mode), 'secret' => Auth::hash($secret), ]); - $membership = $projectDB->createDocument($membership->getArrayCopy()); + if(APP_MODE_ADMIN === $mode) { // Allow admin to create membership + Authorization::disable(); + $membership = $projectDB->createDocument($membership->getArrayCopy()); + Authorization::reset(); + } + else { + $membership = $projectDB->createDocument($membership->getArrayCopy()); + } if (false === $membership) { throw new Exception('Failed saving membership to DB', 500); @@ -334,7 +341,9 @@ $utopia->post('/v1/teams/:teamId/memberships') $mail->AltBody = strip_tags($body->render()); try { - $mail->send(); + if(APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode + $mail->send(); + } } catch (\Exception $error) { throw new Exception('Error sending mail: ' . $error->getMessage(), 500); } From 98846adfc978c1725a19e577f4faef88678406f2 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Tue, 9 Jun 2020 07:27:09 +0300 Subject: [PATCH 19/22] Fixed test --- app/controllers/api/teams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index e235c3536a..a88f8ee2d9 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -341,7 +341,7 @@ $utopia->post('/v1/teams/:teamId/memberships') $mail->AltBody = strip_tags($body->render()); try { - if(APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode + if(!APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode $mail->send(); } } catch (\Exception $error) { From 50e7fc43c90bcd85eea546db4b0be9e77aaa3bd1 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 10 Jun 2020 21:55:22 +0300 Subject: [PATCH 20/22] Fixed test --- app/controllers/api/teams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index a88f8ee2d9..ded2445faa 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -341,7 +341,7 @@ $utopia->post('/v1/teams/:teamId/memberships') $mail->AltBody = strip_tags($body->render()); try { - if(!APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode + if(APP_MODE_ADMIN !== $mode) { // No need in comfirmation when in admin mode $mail->send(); } } catch (\Exception $error) { From f54b662bdb147fdbe699166fa6ae0fd699dc2445 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 10 Jun 2020 21:55:56 +0300 Subject: [PATCH 21/22] Removed debug log --- tests/e2e/Services/Teams/TeamsBaseClient.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 6d6df372a9..ceb0d86e5c 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -234,8 +234,6 @@ trait TeamsBaseClient $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['memberships']); - var_dump($response); - return []; } } \ No newline at end of file From 69f944ec46f1c5e01f8a2cf7210cc523a81d5b8e Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Thu, 11 Jun 2020 10:57:12 +0300 Subject: [PATCH 22/22] Removed gravatar upload button --- app/views/console/account/index.phtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/console/account/index.phtml b/app/views/console/account/index.phtml index 8843636ea3..0e32243377 100644 --- a/app/views/console/account/index.phtml +++ b/app/views/console/account/index.phtml @@ -24,13 +24,13 @@
      User Avatar -
      + - Upload + -
      + - (via gravatar.com ) +
      @@ -57,7 +57,7 @@
      - +
      @@ -85,7 +85,7 @@
      -