This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit e96c19fd58a33e7c3e91ca1f80694961649cd750
Author: Dave Brondsema <[email protected]>
AuthorDate: Fri Jul 29 13:19:46 2022 -0400

    [#8450] make /rest/auth/tools endpoint, refactor repo fields, remove 
old/confusing tool fields
---
 Allura/allura/app.py                               | 10 ++---
 Allura/allura/controllers/auth.py                  | 15 +++++++
 Allura/allura/controllers/repository.py            | 17 +++-----
 Allura/allura/controllers/rest.py                  |  2 +
 Allura/allura/lib/repository.py                    | 10 +++++
 Allura/allura/model/auth.py                        |  7 ++-
 Allura/allura/model/project.py                     | 14 +++---
 Allura/allura/model/repository.py                  |  1 -
 Allura/allura/tests/functional/test_auth.py        | 39 ++++++++++++++++-
 Allura/docs/api-rest/api.raml                      | 27 ++++++++++--
 Allura/docs/api-rest/examples/auth-tools.json      | 22 ++++++++++
 Allura/docs/api-rest/examples/scm.json             |  7 ++-
 Allura/docs/api-rest/schemas/auth-tools.json       | 50 ++++++++++++++++++++++
 Allura/docs/api-rest/schemas/page.json             |  2 +-
 Allura/docs/api-rest/schemas/scm.json              | 26 ++++++++---
 Allura/docs/api-rest/schemas/tickets.json          |  2 +-
 .../forgegit/tests/functional/test_controllers.py  |  9 ++--
 17 files changed, 219 insertions(+), 41 deletions(-)

diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index e2e34db0d..d40668e1b 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -786,15 +786,15 @@ class Application:
 
         Returns dict that will be included in project's API under tools key.
         """
-        return {
+        json = {
             'name': self.config.tool_name,
             'mount_point': self.config.options.mount_point,
-            'url': self.config.url(),
-            'icons': self.icons,
-            'installable': self.installable,
-            'tool_label': self.tool_label,
+            'url': h.absurl(self.config.url()),
             'mount_label': self.config.options.mount_label
         }
+        if self.api_root:
+            json['api_url'] = h.absurl('/rest' + self.config.url())
+        return json
 
     def get_attachment_export_path(self, path='', *args):
         return os.path.join(path, self.config.options.mount_point, *args)
diff --git a/Allura/allura/controllers/auth.py 
b/Allura/allura/controllers/auth.py
index ac0c7b400..e5154f05a 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -554,6 +554,21 @@ class AuthController(BaseController):
             redirect('/')
 
 
+class AuthRestController:
+
+    @expose('json:')
+    def tools(self, tool_type: str):
+        apps = []
+        for p in c.user.my_projects():
+            for ac in p.app_configs:
+                if ac.tool_name == tool_type and h.has_access(ac, 'read'):
+                    apps.append(p.app_instance(ac))
+
+        return {
+            'tools': apps,  # TG automatically runs their __json__ methods
+        }
+
+
 def select_new_primary_addr(user, ignore_emails=[]):
     for obj_e in user.email_addresses:
         obj = user.address_object(obj_e)
diff --git a/Allura/allura/controllers/repository.py 
b/Allura/allura/controllers/repository.py
index 1f769408a..ab98ec1ef 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -313,6 +313,11 @@ class RepoRestController(RepoRootController, 
AppRestControllerMixin):
     def index(self, **kw):
         app: Application = c.app
         repo: M.Repository = app.repo
+
+        # core fields, shared in other API endpoints
+        resp = app.__json__()
+
+        # more expensive fields that we only show in this individual API 
endpoint
         try:
             all_commits = repo._impl.new_commits(all_commits=True)
         except Exception:
@@ -320,16 +325,8 @@ class RepoRestController(RepoRootController, 
AppRestControllerMixin):
             commit_count = None
         else:
             commit_count = len(all_commits)
-        resp = dict(
-            commit_count=commit_count,
-            name=app.config.options.mount_label,
-            type=app.tool_label,
-        )
-        for clone_cat in 
repo.clone_command_categories(anon=c.user.is_anonymous()):
-            respkey = 'clone_url_' + clone_cat['key']
-            resp[respkey] = repo.clone_url(clone_cat['key'],
-                                           username='' if 
c.user.is_anonymous() else c.user.username,
-                                           )
+        resp['commit_count'] = commit_count
+
         return resp
 
     @expose('json:')
diff --git a/Allura/allura/controllers/rest.py 
b/Allura/allura/controllers/rest.py
index c36b45451..5bf4c786c 100644
--- a/Allura/allura/controllers/rest.py
+++ b/Allura/allura/controllers/rest.py
@@ -31,6 +31,7 @@ import colander
 from ming.orm import session
 
 from allura import model as M
+from allura.controllers.auth import AuthRestController
 from allura.lib import helpers as h
 from allura.lib import security
 from allura.lib import plugin
@@ -48,6 +49,7 @@ class RestController:
 
     def __init__(self):
         self.oauth = OAuthNegotiator()
+        self.auth = AuthRestController()
 
     def _check_security(self):
         if not request.path.startswith('/rest/oauth/'):  # everything but 
OAuthNegotiator
diff --git a/Allura/allura/lib/repository.py b/Allura/allura/lib/repository.py
index 24789f971..84441912d 100644
--- a/Allura/allura/lib/repository.py
+++ b/Allura/allura/lib/repository.py
@@ -250,6 +250,16 @@ class RepositoryApp(Application):
     def uninstall(self, project):
         allura.tasks.repo_tasks.uninstall.post()
 
+    def __json__(self):
+        data = super().__json__()
+        repo: M.Repository = self.repo
+        for clone_cat in 
repo.clone_command_categories(anon=c.user.is_anonymous()):
+            respkey = 'clone_url_' + clone_cat['key']
+            data[respkey] = repo.clone_url(clone_cat['key'],
+                                           username='' if 
c.user.is_anonymous() else c.user.username,
+                                           )
+        return data
+
 
 class RepoAdminController(DefaultAdminController):
 
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index ae4b0b402..915b88736 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -15,6 +15,8 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from __future__ import annotations
+
 import logging
 import calendar
 import typing
@@ -56,6 +58,7 @@ from .timeline import ActivityNode, ActivityObject
 
 if typing.TYPE_CHECKING:
     from ming.odm.mapper import Query
+    from allura.model.project import Project
 
 
 log = logging.getLogger(__name__)
@@ -768,9 +771,9 @@ class User(MappedClass, ActivityNode, ActivityObject, 
SearchIndexable):
     def script_name(self):
         return '/u/' + self.username + '/'
 
-    def my_projects(self):
+    def my_projects(self) -> typing.Iterable[Project]:
         if self.is_anonymous():
-            return
+            return []
         roles = g.credentials.user_roles(user_id=self._id)
         # filter out projects to which the user belongs to no named groups 
(i.e., role['roles'] is empty)
         projects = [r['project_id'] for r in roles if r['roles']]
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 0e35ae309..d384b5c01 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -15,9 +15,12 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from __future__ import annotations
+
 import logging
 from calendar import timegm
 from collections import Counter, OrderedDict
+from collections.abc import Iterable
 from hashlib import sha256
 import typing
 from datetime import datetime
@@ -67,6 +70,7 @@ import six
 
 if typing.TYPE_CHECKING:
     from ming.odm.mapper import Query
+    from allura.model import AppConfig
 
 
 log = logging.getLogger(__name__)
@@ -250,7 +254,7 @@ class Project(SearchIndexable, MappedClass, ActivityNode, 
ActivityObject):
     acl = FieldProperty(ACL(permissions=_perms_init))
     neighborhood_invitations = FieldProperty([S.ObjectId])
     neighborhood = RelationProperty(Neighborhood)
-    app_configs = RelationProperty('AppConfig')
+    app_configs: Iterable[AppConfig] = RelationProperty('AppConfig')
     category_id = FieldProperty(S.ObjectId, if_missing=None)
     deleted = FieldProperty(bool, if_missing=False)
     labels = FieldProperty([str])
@@ -899,7 +903,7 @@ class Project(SearchIndexable, MappedClass, ActivityNode, 
ActivityObject):
             app.install(self)
         return app
 
-    def uninstall_app(self, mount_point):
+    def uninstall_app(self, mount_point: str):
         app = self.app_instance(mount_point)
         if app is None:
             return
@@ -908,7 +912,7 @@ class Project(SearchIndexable, MappedClass, ActivityNode, 
ActivityObject):
         with h.push_config(c, project=self, app=app):
             app.uninstall(self)
 
-    def app_instance(self, mount_point_or_config):
+    def app_instance(self, mount_point_or_config: AppConfig | str):
         if isinstance(mount_point_or_config, AppConfig):
             app_config = mount_point_or_config
         else:
@@ -921,12 +925,12 @@ class Project(SearchIndexable, MappedClass, ActivityNode, 
ActivityObject):
         else:
             return App(self, app_config)
 
-    def app_config(self, mount_point):
+    def app_config(self, mount_point: str):
         return AppConfig.query.find({
             'project_id': self._id,
             'options.mount_point': mount_point}).first()
 
-    def app_config_by_tool_type(self, tool_type):
+    def app_config_by_tool_type(self, tool_type: str):
         for ac in self.app_configs:
             if ac.tool_name == tool_type:
                 return ac
diff --git a/Allura/allura/model/repository.py 
b/Allura/allura/model/repository.py
index 0c2239ccc..7ebbffdb7 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -365,7 +365,6 @@ class Repository(Artifact, ActivityObject):
     fs_path = FieldProperty(str)
     url_path = FieldProperty(str)
     status = FieldProperty(str)
-    email_address = ''
     additional_viewable_extensions = FieldProperty(str)
     heads = FieldProperty(S.Deprecated)
     branches = FieldProperty(S.Deprecated)
diff --git a/Allura/allura/tests/functional/test_auth.py 
b/Allura/allura/tests/functional/test_auth.py
index e555cf8de..7766ece84 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -45,7 +45,7 @@ import oauth2
 from allura.tests import TestController
 from allura.tests import decorators as td
 from allura.tests.decorators import audits, out_audits
-from alluratest.controller import setup_trove_categories
+from alluratest.controller import setup_trove_categories, TestRestApiBase
 from allura import model as M
 from allura.lib import plugin
 from allura.lib import helpers as h
@@ -1138,6 +1138,43 @@ class TestAuth(TestController):
         assert_not_equal(r.content_length, 777)
 
 
+class TestAuthRest(TestRestApiBase):
+
+    def test_tools_list_anon(self):
+        resp = self.api_get('/rest/auth/tools/wiki', user='*anonymous')
+        assert_equal(resp.json, {
+            'tools': []
+        })
+
+    def test_tools_list_invalid_tool(self):
+        resp = self.api_get('/rest/auth/tools/af732q9547235')
+        assert_equal(resp.json, {
+            'tools': []
+        })
+
+    @td.with_tool('test', 'Wiki', mount_point='docs', 
mount_label='Documentation')
+    def test_tools_list_wiki(self):
+        resp = self.api_get('/rest/auth/tools/wiki')
+        assert_equal(resp.json, {
+            'tools': [
+                {
+                    'mount_label': 'Wiki',
+                    'mount_point': 'wiki',
+                    'name': 'wiki',
+                    'url': 'http://localhost/adobe/wiki/',
+                    'api_url': 'http://localhost/rest/adobe/wiki/',
+                },
+                {
+                    'mount_label': 'Documentation',
+                    'mount_point': 'docs',
+                    'name': 'wiki',
+                    'url': 'http://localhost/p/test/docs/',
+                    'api_url': 'http://localhost/rest/p/test/docs/',
+                },
+            ]
+        })
+
+
 class TestPreferences(TestController):
     @td.with_user_project('test-admin')
     def test_personal_data(self):
diff --git a/Allura/docs/api-rest/api.raml b/Allura/docs/api-rest/api.raml
index 8167cc437..85742059d 100755
--- a/Allura/docs/api-rest/api.raml
+++ b/Allura/docs/api-rest/api.raml
@@ -17,7 +17,9 @@
 #       under the License.
 #
 #
-# http://apiworkbench.com/ is a useful tool to edit this file
+# https://github.com/mulesoft/api-designer is a useful tool to edit this file
+# web version http://mulesoft.github.io/api-designer/
+# version that works well with local files: 
https://github.com/sichvoge/api-designer-fs but you must change git:// to 
https:// in its package.json before `npm install`
 ---
 title: Apache Allura
 version: 1
@@ -38,6 +40,25 @@ documentation:
   - title: API Overview
     content: !include docs.md
 
+/auth:
+    description: |
+      Authorization related APIs.  See also OAuth
+
+    /tools/{tool_type}:
+      uriParameters:
+        tool_type:
+          type: string
+          example: git
+      type: {
+        generic: {
+          example: !include examples/auth-tools.json,
+          schema: !include schemas/auth-tools.json
+        }
+      }
+      get:
+        description: |
+          List tools (e.g. "git" repos) that the current user is associated 
with
+
 /oauth:
     description: |
       See separate docs section for authenticating with the OAuth 1.0 APIs
@@ -263,7 +284,7 @@ documentation:
                       description: ticket description
                       type: string
                       required: false
-                    ticket_form.assigned_to::
+                    ticket_form.assigned_to:
                       type: string
                       required: false
                       description: username of ticket assignee
@@ -311,7 +332,7 @@ documentation:
                     description: ticket description
                     type: string
                     required: false
-                  ticket_form.assigned_to::
+                  ticket_form.assigned_to:
                     type: string
                     required: false
                     description: username of ticket assignee
diff --git a/Allura/docs/api-rest/examples/auth-tools.json 
b/Allura/docs/api-rest/examples/auth-tools.json
new file mode 100755
index 000000000..cdd569fcf
--- /dev/null
+++ b/Allura/docs/api-rest/examples/auth-tools.json
@@ -0,0 +1,22 @@
+{
+  "tools": [
+    {
+      "url": "https://forge-allura.apache.org/p/test/code/";,
+      "api_url": "https://forge-allura.apache.org/rest/p/test/code/";,
+      "mount_label": "Code",
+      "mount_point": "code",
+      "name": "git",
+      "clone_url_https_anon": 
"https://forge-allura.apache.org/git/p/test/code/";,
+      "clone_url_ro": "git://forge-allura.apache.org/git/p/test/code"
+    },
+    {
+      "url": "https://forge-allura.apache.org/u/someuser/widgets-fork/";,
+      "api_url": 
"https://forge-allura.apache.org/rest/u/someuser/widgets-fork/";,
+      "mount_label": "Widgets - Fork",
+      "mount_point": "widgets-fork",
+      "name": "git",
+      "clone_url_https_anon": 
"https://forge-allura.apache.org/git/u/someuser/widgets-fork";,
+      "clone_url_ro": 
"git://forge-allura.apache.org/git/u/someuser/widgets-fork"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/Allura/docs/api-rest/examples/scm.json 
b/Allura/docs/api-rest/examples/scm.json
index a5a2f4b4e..7718a397f 100755
--- a/Allura/docs/api-rest/examples/scm.json
+++ b/Allura/docs/api-rest/examples/scm.json
@@ -1,6 +1,9 @@
 {
-  "name": "Code",
-  "type": "Git",
+  "url": "https://forge-allura.apache.org/p/test/code/";,
+  "api_url": "https://forge-allura.apache.org/rest/p/test/code/";,
+  "mount_label": "Code",
+  "mount_point": "code",
+  "name": "git",
   "commit_count": 17,
   "clone_url_https_anon": "https://forge-allura.apache.org/git/p/test/code";,
   "clone_url_ro": "git://forge-allura.apache.org/git/p/test/code"
diff --git a/Allura/docs/api-rest/schemas/auth-tools.json 
b/Allura/docs/api-rest/schemas/auth-tools.json
new file mode 100755
index 000000000..5de2ae579
--- /dev/null
+++ b/Allura/docs/api-rest/schemas/auth-tools.json
@@ -0,0 +1,50 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema";,
+    "type": "object",
+    "id": "#",
+    "properties": {
+        "tools": {
+            "items": {
+                "type": "object",
+                "id": "0",
+                "properties": {
+                    "url": {
+                        "type": "string",
+                        "id": "url"
+                    },
+                    "api_url": {
+                        "type": "string",
+                        "id": "api_url"
+                    },
+                    "mount_label": {
+                        "type": "string",
+                        "id": "mount_label"
+                    },
+                    "mount_point": {
+                        "type": "string",
+                        "id": "mount_point"
+                    },
+                    "name": {
+                        "type": "string",
+                        "id": "name"
+                    },
+                    "clone_url_https_anon": {
+                        "type": "string",
+                        "id": "clone_url_https_anon"
+                    },
+                    "clone_url_ro": {
+                        "type": "string",
+                        "id": "clone_url_ro"
+                    },
+                    "clone_url_*": {
+                        "type": "string",
+                        "id": "clone_url_*"
+                    }
+                }
+            },
+            "type": "array",
+            "id": "tools"
+        }
+    }
+}
+       
\ No newline at end of file
diff --git a/Allura/docs/api-rest/schemas/page.json 
b/Allura/docs/api-rest/schemas/page.json
index d9611450b..c54240e3e 100755
--- a/Allura/docs/api-rest/schemas/page.json
+++ b/Allura/docs/api-rest/schemas/page.json
@@ -4,7 +4,7 @@
   "properties": {
     "related_artifacts": {
       "items": {
-        "type": ["null", "string"],
+        "type": ["null", "string"]
       },
       "type": ["null", "array"],
       "id": "related_artifacts"
diff --git a/Allura/docs/api-rest/schemas/scm.json 
b/Allura/docs/api-rest/schemas/scm.json
index 0a69b65e7..b686e796a 100755
--- a/Allura/docs/api-rest/schemas/scm.json
+++ b/Allura/docs/api-rest/schemas/scm.json
@@ -3,13 +3,25 @@
     "type": "object",
     "id": "#",
     "properties": {
-        "name": {
+        "url": {
             "type": "string",
-            "id": "name"
+            "id": "url"
+        },
+        "api_url": {
+            "type": "string",
+            "id": "api_url"
         },
-        "type": {
+        "mount_label": {
             "type": "string",
-            "id": "type"
+            "id": "mount_label"
+        },
+        "mount_point": {
+            "type": "string",
+            "id": "mount_point"
+        },
+        "name": {
+            "type": "string",
+            "id": "name"
         },
         "commit_count": {
             "type": "integer",
@@ -17,15 +29,15 @@
         },
         "clone_url_https_anon": {
             "type": "string",
-            "id": "name"
+            "id": "clone_url_https_anon"
         },
         "clone_url_ro": {
             "type": "string",
-            "id": "name"
+            "id": "clone_url_ro"
         },
         "clone_url_*": {
             "type": "string",
-            "id": "name"
+            "id": "clone_url_*"
         }
     }
 }
diff --git a/Allura/docs/api-rest/schemas/tickets.json 
b/Allura/docs/api-rest/schemas/tickets.json
index 6a68c2cd8..a30e01c74 100755
--- a/Allura/docs/api-rest/schemas/tickets.json
+++ b/Allura/docs/api-rest/schemas/tickets.json
@@ -46,7 +46,7 @@
                 },
                 "default": {
                   "id": "default",
-                  "type": ""
+                  "type": "string"
                 },
                 "description": {
                   "id": "description",
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py 
b/ForgeGit/forgegit/tests/functional/test_controllers.py
index f4854db25..2bc49ed68 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -556,10 +556,13 @@ class TestRestController(_TestCase):
     def test_index(self):
         resp = self.app.get('/rest/p/test/src-git/', status=200)
         assert_equal(resp.json, {
+            'api_url': 'http://localhost/rest/p/test/src-git/',
+            'url': 'http://localhost/p/test/src-git/',
+            'mount_label': 'Git',
+            'mount_point': 'src-git',
+            'name': 'git',
+            'clone_url_file': '/srv/git/p/test/testgit',  # should be 
"src-git" but test data is weird?
             'commit_count': 5,
-            'name': 'Git',
-            'type': 'Git',
-            'clone_url_file': '/srv/git/p/test/testgit',
         })
 
     def test_commits(self):

Reply via email to