Skip to content

Commit

Permalink
add swagger to project api
Browse files Browse the repository at this point in the history
  • Loading branch information
n00rsy committed Aug 16, 2023
1 parent e68add7 commit b7f77cb
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 52 deletions.
160 changes: 118 additions & 42 deletions pybossa/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,41 +43,42 @@
from pybossa.util import get_disqus_sso_payload, grant_access_with_api_key
import dateutil.parser
import pybossa.model as model
import pybossa.model.project as projectModel
from pybossa.core import csrf, ratelimits, sentinel, anonymizer
from pybossa.ratelimit import ratelimit
from pybossa.cache.projects import n_tasks, n_completed_tasks
import pybossa.sched as sched
from pybossa.util import sign_task, can_update_user_info
from pybossa.error import ErrorStatus
from .global_stats import GlobalStatsAPI
from .task import TaskAPI
from .task_run import TaskRunAPI, preprocess_task_run
# from .global_stats import GlobalStatsAPI
# from .task import TaskAPI
# from .task_run import TaskRunAPI, preprocess_task_run
from .project import ProjectAPI
from .auditlog import AuditlogAPI
from .announcement import AnnouncementAPI
from .blogpost import BlogpostAPI
# from .auditlog import AuditlogAPI
# from .announcement import AnnouncementAPI
# from .blogpost import BlogpostAPI
from .category import CategoryAPI
from .favorites import FavoritesAPI
from pybossa.api.performance_stats import PerformanceStatsAPI
from .user import UserAPI
from .token import TokenAPI
from .result import ResultAPI
# from .favorites import FavoritesAPI
# from pybossa.api.performance_stats import PerformanceStatsAPI
# from .user import UserAPI
# from .token import TokenAPI
# from .result import ResultAPI
from rq import Queue
from .project_stats import ProjectStatsAPI
from .helpingmaterial import HelpingMaterialAPI
# from .project_stats import ProjectStatsAPI
# from .helpingmaterial import HelpingMaterialAPI
from pybossa.core import auditlog_repo, project_repo, task_repo, user_repo
from pybossa.contributions_guard import ContributionsGuard
from pybossa.auth import jwt_authorize_project
from werkzeug.exceptions import MethodNotAllowed, Forbidden
from .completed_task import CompletedTaskAPI
from .completed_task_run import CompletedTaskRunAPI
# from .completed_task import CompletedTaskAPI
# from .completed_task_run import CompletedTaskRunAPI
from pybossa.cache.helpers import (n_available_tasks, n_available_tasks_for_user,
n_unexpired_gold_tasks)
from pybossa.sched import (get_scheduler_and_timeout, has_lock, release_lock, Schedulers,
fetch_lock_for_user, release_reserve_task_lock_by_id)
from pybossa.jobs import send_mail
from pybossa.api.project_by_name import ProjectByNameAPI, project_name_to_oid
from pybossa.api.project_details import ProjectDetailsAPI
# from pybossa.api.project_details import ProjectDetailsAPI
from pybossa.api.pwd_manager import get_pwd_manager
from pybossa.data_access import data_access_levels
from pybossa.task_creator_helper import set_gold_answers
Expand All @@ -92,7 +93,11 @@
from pybossa.cache.users import get_user_pref_metadata
from pybossa.view.projects import get_locked_tasks
from pybossa.redis_lock import EXPIRE_LOCK_DELAY
from pybossa.api.bulktasks import BulkTasksAPI
#from pybossa.api.bulktasks import BulkTasksAPI

from flask_openapi3 import Tag, APIBlueprint
from pydantic import BaseModel, Field
from typing import Optional

task_fields = [
"id",
Expand All @@ -102,13 +107,33 @@
"calibration",
]

blueprint = Blueprint('api', __name__)
#blueprint = Blueprint('api', __name__)

tag = Tag(name='api', description="GIGwork API")

blueprint = APIBlueprint(
'/api',
__name__,
abp_tags=[tag],
doc_ui=True
)

class BookBody(BaseModel):
"""a book."""
age: Optional[int] = Field(..., ge=2, le=4, description='Age')
author: str = Field(None, min_length=2, max_length=4, description='Author')

@blueprint.post('/book', responses={201: {"content": {"text/csv": {"schema": {"type": "string"}}}, "description": "gotem"}})
def create_book(body: BookBody):
"""create a book."""
assert body.age == 3
return {"code": 0, "message": "ok"}

error = ErrorStatus()
mail_queue = Queue('email', connection=sentinel.master)


@blueprint.route('/')
@blueprint.get('/', responses={200: {"content": {"text/html": {"schema": {"type": "string"}}}, "description": "pybossa home page"}})
@ratelimit(limit=ratelimits.get('LIMIT'), per=ratelimits.get('PER'))
def index(): # pragma: no cover
"""Return dummy text for welcome page."""
Expand Down Expand Up @@ -142,29 +167,80 @@ def register_api(view, endpoint, url, pk='id', pk_type='int'):
view_func=view_func,
methods=['GET', 'PUT', 'DELETE', 'OPTIONS'])

register_api(ProjectAPI, 'api_project', '/project', pk='oid', pk_type='int')
register_api(ProjectStatsAPI, 'api_projectstats', '/projectstats', pk='oid', pk_type='int')
register_api(CategoryAPI, 'api_category', '/category', pk='oid', pk_type='int')
register_api(TaskAPI, 'api_task', '/task', pk='oid', pk_type='int')
register_api(AuditlogAPI, 'api_auditlog', '/auditlog', pk='oid', pk_type='int')
register_api(TaskRunAPI, 'api_taskrun', '/taskrun', pk='oid', pk_type='int')
register_api(ResultAPI, 'api_result', '/result', pk='oid', pk_type='int')
register_api(UserAPI, 'api_user', '/user', pk='oid', pk_type='int')
register_api(AnnouncementAPI, 'api_announcement', '/announcement', pk='oid', pk_type='int')
register_api(BlogpostAPI, 'api_blogpost', '/blogpost', pk='oid', pk_type='int')
register_api(HelpingMaterialAPI, 'api_helpingmaterial',
'/helpingmaterial', pk='oid', pk_type='int')
register_api(GlobalStatsAPI, 'api_globalstats', '/globalstats',
pk='oid', pk_type='int')
register_api(FavoritesAPI, 'api_favorites', '/favorites',
pk='oid', pk_type='int')
register_api(TokenAPI, 'api_token', '/token', pk='token', pk_type='string')
register_api(CompletedTaskAPI, 'api_completedtask', '/completedtask', pk='oid', pk_type='int')
register_api(CompletedTaskRunAPI, 'api_completedtaskrun', '/completedtaskrun', pk='oid', pk_type='int')
register_api(ProjectByNameAPI, 'api_projectbyname', '/projectbyname', pk='key', pk_type='string')
register_api(ProjectDetailsAPI, 'api_projectdetails', '/projectdetails', pk='oid', pk_type='int')
register_api(PerformanceStatsAPI, 'api_performancestats', '/performancestats', pk='oid', pk_type='int')
register_api(BulkTasksAPI, 'api_bulktasks', '/bulktasks', pk='oid', pk_type='int')
projectAPI = ProjectAPI()
categoryAPI = CategoryAPI()

class getProjectBody(BaseModel):
oid: int = Field(..., description='Project ID')


class DataClassification(BaseModel):
input_data: str
output_data: str

class Info(BaseModel):
subproduct: str
product: str
kpi: int
data_classification: DataClassification

class createProjectBody(BaseModel):
name: str
short_name: str
description: str
password: str
info: Info


@blueprint.get('/project/<int:oid>', endpoint='api_project',
responses={200: {"content": {"application/json": {}}, "description": "success"}},
description="get a project")
def get_project(path: getProjectBody):
print("GET /project: ", type(path), path)
return projectAPI.get(oid=path.oid)

@csrf.exempt
@blueprint.post('/project',
responses={200: {"content": {"application/json": {}}, "description": "success"}},
description="create a project",)
def post_project(body: createProjectBody):
print("POST /project: ", body)
return projectAPI.post()

@blueprint.delete('/project/<int:oid>', description="delete a project.")
def delete_project(path: getProjectBody):
print("DELETE /project: ", type(path), path)
return projectAPI.delete(oid=path.oid)

@csrf.exempt
@blueprint.get('/category/<int:oid>', endpoint='api_category', responses={200: {"content": {"application/json": {"schema": {"type": "string"}}}, "description": "success"}})
def get_category(path: getProjectBody):
print("GET /category: ", type(path), path)
return categoryAPI.get(oid=path.oid)

# register_api(ProjectAPI, 'api_project', '/project', pk='oid', pk_type='int')
# register_api(ProjectStatsAPI, 'api_projectstats', '/projectstats', pk='oid', pk_type='int')
# register_api(CategoryAPI, 'api_category', '/category', pk='oid', pk_type='int')
# register_api(TaskAPI, 'api_task', '/task', pk='oid', pk_type='int')
# register_api(AuditlogAPI, 'api_auditlog', '/auditlog', pk='oid', pk_type='int')
# register_api(TaskRunAPI, 'api_taskrun', '/taskrun', pk='oid', pk_type='int')
# register_api(ResultAPI, 'api_result', '/result', pk='oid', pk_type='int')
# register_api(UserAPI, 'api_user', '/user', pk='oid', pk_type='int')
# register_api(AnnouncementAPI, 'api_announcement', '/announcement', pk='oid', pk_type='int')
# register_api(BlogpostAPI, 'api_blogpost', '/blogpost', pk='oid', pk_type='int')
# register_api(HelpingMaterialAPI, 'api_helpingmaterial',
# '/helpingmaterial', pk='oid', pk_type='int')
# register_api(GlobalStatsAPI, 'api_globalstats', '/globalstats',
# pk='oid', pk_type='int')
# register_api(FavoritesAPI, 'api_favorites', '/favorites',
# pk='oid', pk_type='int')
# register_api(TokenAPI, 'api_token', '/token', pk='token', pk_type='string')
# register_api(CompletedTaskAPI, 'api_completedtask', '/completedtask', pk='oid', pk_type='int')
# register_api(CompletedTaskRunAPI, 'api_completedtaskrun', '/completedtaskrun', pk='oid', pk_type='int')
# register_api(ProjectByNameAPI, 'api_projectbyname', '/projectbyname', pk='key', pk_type='string')
# register_api(ProjectDetailsAPI, 'api_projectdetails', '/projectdetails', pk='oid', pk_type='int')
# register_api(PerformanceStatsAPI, 'api_performancestats', '/performancestats', pk='oid', pk_type='int')
# register_api(BulkTasksAPI, 'api_bulktasks', '/bulktasks', pk='oid', pk_type='int')


def add_task_signature(tasks):
Expand Down
1 change: 1 addition & 0 deletions pybossa/api/api_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def get(self, oid):
:returns: The JSON item/s stored in the DB
"""
print("GET method got: ", oid)
try:
ensure_authorized_to('read', self.__class__)
query = self._db_query(oid)
Expand Down
3 changes: 2 additions & 1 deletion pybossa/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@
import json
from pybossa.wizard import Wizard

from flask_openapi3 import OpenAPI

def create_app(run_as_server=True):
"""Create web app."""

setup_logging(run_as_server)
app = Flask(__name__.split('.')[0])
app = OpenAPI(__name__.split('.')[0])
configure_app(app)
global talisman
talisman = Talisman(app, content_security_policy={
Expand Down
2 changes: 2 additions & 0 deletions pybossa/hateoas.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def link(self, rel, title, href):
def create_link(self, item_id, title, rel='self'):
"""Create hateoas link."""
# title = item.__class__.__name__.lower()
print("create_link args: ", item_id, title, rel)
method = ".api_%s" % title
href = url_for(method, oid=item_id, _external=True)
return self.link(rel, title, href)
Expand All @@ -38,6 +39,7 @@ def create_links(self, item):
"""Create Hateoas links."""
cls = item.__class__.__name__.lower()
links = []
print("CLS IS ", cls)
if cls == 'result':
link = self. create_link(item.id, title='result')
if item.project_id is not None:
Expand Down
44 changes: 39 additions & 5 deletions pybossa/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,45 @@
# You should have received a copy of the GNU Affero General Public License
# along with PYBOSSA. If not, see <http://www.gnu.org/licenses/>.
from pybossa.core import create_app
from flask_openapi3 import OpenAPI

if __name__ == "__main__": # pragma: no cover
def get_app():
app = create_app()
# logging.basicConfig(level=logging.NOTSET)
app.run(host=app.config['HOST'], port=app.config['PORT'],
debug=app.config.get('DEBUG', True))
# app = OpenAPI(__name__)

from pybossa.api import blueprint as api
from pybossa.view.test_view import blueprint as test

blueprints = [
# {'handler': home, 'url_prefix': '/'},
# {'handler': api, 'url_prefix': '/api'},
# {'handler': account, 'url_prefix': '/account'},
# {'handler': bloomberg, 'url_prefix': '/bloomberg'},
# {'handler': projects, 'url_prefix': '/project'},
# {'handler': projectids, 'url_prefix': '/projectid'},
# {'handler': admin, 'url_prefix': '/admin'},
# {'handler': announcements, 'url_prefix': '/announcements'},
# {'handler': leaderboard, 'url_prefix': '/leaderboard'},
# {'handler': helper, 'url_prefix': '/help'},
# {'handler': stats, 'url_prefix': '/stats'},
# {'handler': uploads, 'url_prefix': '/uploads'},
# {'handler': amazon, 'url_prefix': '/amazon'},
# {'handler': diagnostics, 'url_prefix': '/diagnostics'},
# {'handler': fileproxy, 'url_prefix': '/fileproxy'}

{'handler': api, 'url_prefix': '/api'},
{'handler': test, 'url_prefix': '/test'}
]


for bp in blueprints:
print("registering: ", bp)
app.register_api(bp['handler'])
print([str(p) for p in app.url_map.iter_rules()])
return app

if __name__ == "__main__": # pragma: no cover
app = get_app()
app.run(debug=True)
else:
app = create_app()
app = get_app()
2 changes: 1 addition & 1 deletion pybossa/themes/default
5 changes: 2 additions & 3 deletions pybossa/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,8 @@ def is_reserved_name(blueprint, name):
path = ''.join(['/', blueprint])
app_urls = [r.rule for r in current_app.url_map.iter_rules()
if r.rule.startswith(path)]
reserved_names = [url.split('/')[2] for url in app_urls
if url.split('/')[2] != '']
return name in reserved_names

return False


def username_from_full_name(username):
Expand Down
1 change: 1 addition & 0 deletions pybossa/view/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from jinja2.exceptions import TemplateNotFound
from .projects import index as project_index


blueprint = Blueprint('home', __name__)


Expand Down
23 changes: 23 additions & 0 deletions pybossa/view/test_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from flask_openapi3 import Tag, APIBlueprint
from flask import request
from pydantic import BaseModel, Field
from typing import Optional

tag = Tag(name='book', description="Some Book")

class BookPath(BaseModel):
id: int = Field(..., description="book ID")

blueprint = APIBlueprint(
'/book',
__name__,
url_prefix='/books',
abp_tags=[tag],
doc_ui=True
)

@blueprint.get('/book/<int:id>')
def get_book(path: BookPath):
"""get a book."""
print("GOT ID:", path)
return {"code": 0, "message": "ok", "book":"Harry Potter"}

0 comments on commit b7f77cb

Please sign in to comment.