Skip to content

Commit

Permalink
Merge branch 'knivets-api_docs'
Browse files Browse the repository at this point in the history
  • Loading branch information
smirolo committed Jul 16, 2019
2 parents e9e6d2b + 5de737b commit 0efd1b8
Show file tree
Hide file tree
Showing 11 changed files with 11,801 additions and 22 deletions.
5 changes: 5 additions & 0 deletions Makefile
Expand Up @@ -103,6 +103,11 @@ makemessages:
cd $(srcDir) && $(PYTHON) manage.py makemessages -d djangojs -l fr -l es -l pt --symlinks --no-wrap


generateschema:
cd $(srcDir) && $(PYTHON) manage.py generateschema --url http://cowork.djaoapp.com > schema.yml
cd $(srcDir) && swagger-cli validate schema.yml


migratedb-cowork: initdb-cowork
@echo "-- Set streetside processor deposit key."
$(SQLITE) $(call MULTITIER_DB_NAME) "UPDATE saas_organization set processor_deposit_key='$(shell grep ^STRIPE_TEST_CONNECTED_KEY $(CONFIG_DIR)/credentials | cut -f 2 -d \")' where is_provider=1;"
Expand Down
26 changes: 26 additions & 0 deletions djaoapp/api/custom_themes.py
Expand Up @@ -19,4 +19,30 @@ def theme(self):


class AppUpdateAPIView(RulesAppUpdateAPIView):
"""
Returns the URL endpoint to which requests passing the access rules
are forwarded to, and the format in which the session information
is encoded.
When running tests, you can retrieve the actual session information
for a specific user through the `/proxy/sessions/{user}/` API call.
**Tags: rbac
**Examples
.. code-block:: http
GET /api/proxy/ HTTP/1.1
responds
.. code-block:: json
{
"slug": "cowork",
"entry_point": "http://localhost:8001/",
"session_backend": 1
}
"""
serializer_class = AppSerializer
7 changes: 7 additions & 0 deletions djaoapp/api/notifications.py
Expand Up @@ -96,6 +96,13 @@ def post(self, request, *args, **kwargs):#pylint:disable=unused-argument
POST /api/notifications/contact_requested_notice/ HTTP/1.1
responds
.. code-block:: json
{
"details": "Test email sent to xia@example.com"
}
"""
try:
app = get_current_app()
Expand Down
14 changes: 14 additions & 0 deletions djaoapp/api/organizations.py
Expand Up @@ -38,6 +38,18 @@ class OrganizationDetailAPIView(OrganizationDetailBaseAPIView):
"full_name": "Xia Lee",
"printable_name": "Xia Lee",
"slug": "xia",
"phone": "555-555-5555",
"street_address": "185 Berry St #550",
"locality": "San Francisco",
"region": "CA",
"postal_code": "",
"country": "US",
"default_timezone": "Europe/Kiev",
"is_provider": false,
"is_bulk_buyer": false,
"type": "",
"picture": "",
"extra": "",
"subscriptions": [
{
"created_at": "2018-01-01T00:00:00Z",
Expand All @@ -63,6 +75,8 @@ def put(self, request, *args, **kwargs):
PUT /api/profile/xia/ HTTP/1.1
responds
.. code-block:: json
{
Expand Down
2 changes: 1 addition & 1 deletion djaoapp/api/roles.py
Expand Up @@ -57,7 +57,7 @@ class RoleListAPIView(RoleListBaseAPIView):
},
"request_key": "1",
"grant_key": null
},
}
]
}
"""
Expand Down
44 changes: 36 additions & 8 deletions djaoapp/api/users.py
Expand Up @@ -7,7 +7,7 @@

from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
from rest_framework.generics import GenericAPIView
from rest_framework.generics import ListAPIView
from rest_framework.response import Response

from saas.models import Charge
Expand Down Expand Up @@ -37,9 +37,9 @@ class UserProfileAPIView(UserProfileBaseAPIView):
.. code-block:: json
{
"username": "donny",
"email": "donny.smith@example.com"
"full_name": "Donny Smith"
"username": "donny",
"email": "donny.smith@locahost.localdomain",
"full_name": "Donny Smith"
}
"""
def perform_destroy(self, instance):
Expand All @@ -52,10 +52,39 @@ def perform_destroy(self, instance):
super(UserProfileAPIView, self).perform_destroy(instance)


class RecentActivityAPIView(GenericAPIView):
class RecentActivityAPIView(ListAPIView):
"""
Retrieves recently active users
**Tags: metrics
**Example
.. code-block:: http
GET /api/proxy/recent/ HTTP/1.1
responds
.. code-block:: json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"printable_name": "Alice Cooper",
"descr": "recently logged in",
"created_at": "2019-07-15T20:40:29.509572Z",
"slug": "alice"
}
]
}
"""
serializer_class = ActivitySerializer

def get(self, request, *args, **kwargs):
def get_queryset(self):
start_at = day_periods()[0]
users = get_user_model().objects.filter(
last_login__gt=start_at).order_by('-last_login')[:5]
Expand All @@ -79,5 +108,4 @@ def get(self, request, *args, **kwargs):
# TODO 404 for some of the slugs
'slug': charge.customer.slug}
data = sorted(data.values(), key=itemgetter('printable_name'))
return Response({'results':
self.get_serializer(data, many=True).data})
return data
32 changes: 30 additions & 2 deletions djaoapp/management/commands/generate_api_examples.py
Expand Up @@ -2,6 +2,7 @@
# see LICENSE

import json, logging, re
from hashlib import sha256

from django.conf import settings
from django.core.management.base import BaseCommand
Expand All @@ -23,19 +24,46 @@ def add_arguments(self, parser):
parser.add_argument('--provider',
action='store', dest='provider', default=settings.APP_NAME,
help='create sample subscribers on this provider')
parser.add_argument('--errors', action='store_true', default=False,
help='toggle errors')

def handle(self, *args, **options):
formatted_examples = []
api_base_url = getattr(settings, 'API_BASE_URL', '/api')
api_base_url = getattr(settings,
'API_BASE_URL', 'https://djaodjin.com/api')
generator = APIDocGenerator(info=OPENAPI_INFO, url=api_base_url)
schema = generator.get_schema(request=None, public=True)
descr_hashes = []
for path, path_details in schema.paths.items():
for func, func_details in path_details.items():
try:
func_tags, summary, description, examples = \
split_descr_and_examples(func_details,
api_base_url=api_base_url)
formatted_examples += format_examples(examples)
func_examples = format_examples(examples)
hsh = sha256(func_details.description.encode()).hexdigest()
errors = []
if func_examples[0]['path']:
if ('responds' not in examples and func != 'DELETE'):
errors.append('missing-response')
else:
func_examples[0]['path'] = path
func_examples[0]['func'] = func
if not description and not examples:
errors.append('undocumented')
else:
errors.append('parsing')
if hsh in descr_hashes:
errors.append('duplicate-description')
else:
descr_hashes.append(hsh)
if options['errors']:
if errors:
func_examples[0]['errors'] = errors
formatted_examples += func_examples
else:
if not errors:
formatted_examples += func_examples
except AttributeError:
pass
self.stdout.write(json.dumps(formatted_examples, indent=2))
5 changes: 2 additions & 3 deletions djaoapp/templates/docs/api.html
Expand Up @@ -165,9 +165,8 @@
<section class="row">
<div class="col-sm-7">
<a name="{{api_end_point.operationId}}"></a><h3 class="mt-4">{{api_end_point.summary}} <a href="#{{api_end_point.operationId}}" class="header-anchor"><i class="fa fa-link"></i></a></h3>
<pre>
{{api_end_point.func|upper}} {{api_end_point.path}}
</pre>
<pre class="end-point-url" style="background:#eee;">
{{api_end_point.func|upper}} {{api_end_point.path}}</pre>
<div>
{{api_end_point.description}}
</div>
Expand Down
23 changes: 16 additions & 7 deletions djaoapp/views/docs.py
Expand Up @@ -151,8 +151,9 @@ def format_examples(examples):
# in_respoonse
IN_URL_STATE = 0
IN_REQUEST_PARAMS_STATE = 1
IN_RESPONSE_STATE = 2
IN_RESPONSE_EXAMPLE_STATE = 3
IN_REQUEST_PARAMS_EXAMPLE_STATE = 2
IN_RESPONSE_STATE = 3
IN_RESPONSE_EXAMPLE_STATE = 4

formatted_examples = []
state = IN_URL_STATE
Expand All @@ -162,7 +163,7 @@ def format_examples(examples):
resp = ""
for line in examples.splitlines():
line = line.strip()
look = re.match(r'(GET|POST|PUT|PATCH)\s+(\S+)\s+HTTP', line)
look = re.match(r'(GET|POST|PUT|PATCH|DELETE)\s+(\S+)\s+HTTP', line)
if look:
func = look.group(1)
path = look.group(2)
Expand All @@ -176,13 +177,21 @@ def format_examples(examples):
continue
look = re.match('.. code-block::', line)
if look:
if state == IN_REQUEST_PARAMS_STATE:
state = IN_REQUEST_PARAMS_EXAMPLE_STATE
if state == IN_RESPONSE_STATE:
state = IN_RESPONSE_EXAMPLE_STATE
continue
if state == IN_REQUEST_PARAMS_STATE:
request_params += line
if state == IN_REQUEST_PARAMS_EXAMPLE_STATE:
if not request_params or line.strip():
request_params += line
else:
state = IN_REQUEST_PARAMS_STATE
elif state == IN_RESPONSE_EXAMPLE_STATE:
resp += line
if not resp or line.strip():
resp += line
else:
state = IN_RESPONSE_STATE
formatted_example = {'func': func, 'path': path}
if request_params:
try:
Expand Down Expand Up @@ -256,7 +265,7 @@ def split_descr_and_examples(func_details, api_base_url=None):
in_examples = True
sep = ""
elif in_examples:
for method in ('GET', 'POST', 'PUT', 'PATCH'):
for method in ('GET', 'POST', 'PUT', 'PATCH', 'DELETE'):
look = re.match(r'.* (%s /api)' % method, line)
if look:
line = line.replace(look.group(1),
Expand Down

0 comments on commit 0efd1b8

Please sign in to comment.