Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Remove Rest Api module #1119

Merged
merged 13 commits into from
Mar 12, 2021
Merged
4 changes: 2 additions & 2 deletions pype/hosts/maya/plugins/create/create_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,9 @@ def _show_login(self):
# authentication token expired so we need to login to Muster
# again to get it. We use Pype API call to show login window.
api_url = "{}/muster/show_login".format(
os.environ["PYPE_REST_API_URL"])
os.environ["PYPE_WEBSERVER_URL"])
self.log.debug(api_url)
login_response = self._requests_post(api_url, timeout=1)
login_response = self._requests_get(api_url, timeout=1)
if login_response.status_code != 200:
self.log.error("Cannot show login form to Muster")
raise Exception("Cannot show login form to Muster")
Expand Down
4 changes: 2 additions & 2 deletions pype/hosts/maya/plugins/create/create_vrayscene.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,9 @@ def _show_login(self):
# authentication token expired so we need to login to Muster
# again to get it. We use Pype API call to show login window.
api_url = "{}/muster/show_login".format(
os.environ["PYPE_REST_API_URL"])
os.environ["PYPE_WEBSERVER_URL"])
self.log.debug(api_url)
login_response = self._requests_post(api_url, timeout=1)
login_response = self._requests_get(api_url, timeout=1)
if login_response.status_code != 200:
self.log.error("Cannot show login form to Muster")
raise Exception("Cannot show login form to Muster")
Expand Down
4 changes: 2 additions & 2 deletions pype/hosts/maya/plugins/publish/validate_muster_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ def repair(cls, instance):
Renew authentication token by logging into Muster
"""
api_url = "{}/muster/show_login".format(
os.environ["PYPE_REST_API_URL"])
os.environ["PYPE_WEBSERVER_URL"])
cls.log.debug(api_url)
response = cls._requests_post(api_url, timeout=1)
response = cls._requests_get(api_url, timeout=1)
if response.status_code != 200:
cls.log.error('Cannot show login form to Muster')
raise Exception('Cannot show login form to Muster')
Expand Down
2 changes: 1 addition & 1 deletion pype/hosts/premiere/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def clearing_caches_ui():

def test_rest_api_server(env):
# from pprint import pformat
rest_url = env.get("PYPE_REST_API_URL")
rest_url = env.get("PYPE_WEBSERVER_URL")
project_name = "{AVALON_PROJECT}".format(**env)
URL = "/".join((rest_url,
"avalon/projects",
Expand Down
2 changes: 1 addition & 1 deletion pype/hosts/premiere/ppro/js/pype_restapi_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PypeRestApiClient {
* @return {url string}
*/
_getApiServerUrl() {
var url = this.env.PYPE_REST_API_URL;
var url = this.env.PYPE_WEBSERVER_URL;
return url
}

Expand Down
14 changes: 6 additions & 8 deletions pype/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
SettingsAction,
LocalSettingsAction
)
from .rest_api import (
RestApiModule,
IRestApi
from .webserver import (
WebServerModule,
IWebServerRoutes
)
from .user import (
UserModule,
Expand All @@ -40,7 +40,6 @@
from .muster import MusterModule
from .deadline import DeadlineModule
from .standalonepublish_action import StandAlonePublishAction
from .webserver import WebServerModule
from .sync_server import SyncServer


Expand All @@ -57,6 +56,9 @@
"SettingsAction",
"LocalSettingsAction",

"WebServerModule",
"IWebServerRoutes",

"UserModule",
"IUserModule",

Expand All @@ -66,9 +68,6 @@
"TimersManager",
"ITimersManager",

"RestApiModule",
"IRestApi",

"AvalonModule",
"LauncherAction",

Expand All @@ -82,6 +81,5 @@
"DeadlineModule",
"StandAlonePublishAction",

"WebServerModule",
"SyncServer"
)
12 changes: 7 additions & 5 deletions pype/modules/avalon_apps/avalon_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from .. import (
PypeModule,
ITrayModule,
IRestApi
IWebServerRoutes
)


class AvalonModule(PypeModule, ITrayModule, IRestApi):
class AvalonModule(PypeModule, ITrayModule, IWebServerRoutes):
name = "avalon"

def initialize(self, modules_settings):
Expand Down Expand Up @@ -74,10 +74,12 @@ def tray_init(self):
def connect_with_modules(self, _enabled_modules):
return

def rest_api_initialization(self, rest_api_module):
def webserver_initialization(self, server_manager):
"""Implementation of IWebServerRoutes interface."""

if self.tray_initialized:
from .rest_api import AvalonRestApi
self.rest_api_obj = AvalonRestApi()
from .rest_api import AvalonRestApiResource
self.rest_api_obj = AvalonRestApiResource(self, server_manager)

# Definition of Tray menu
def tray_menu(self, tray_menu):
Expand Down
209 changes: 135 additions & 74 deletions pype/modules/avalon_apps/rest_api.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,146 @@
import os
import re
import json
import datetime

import bson
from bson.objectid import ObjectId
import bson.json_util
from pype.modules.rest_api import RestApi, abort, CallbackResult
from avalon.api import AvalonMongoDB

from aiohttp.web_response import Response

class AvalonRestApi(RestApi):
from avalon.api import AvalonMongoDB
from pype.modules.webserver.base_routes import RestApiEndpoint


class _RestApiEndpoint(RestApiEndpoint):
def __init__(self, resource):
self.resource = resource
super(_RestApiEndpoint, self).__init__()

@property
def dbcon(self):
return self.resource.dbcon


class AvalonProjectsEndpoint(_RestApiEndpoint):
async def get(self) -> Response:
output = []
for project_name in self.dbcon.database.collection_names():
project_doc = self.dbcon.database[project_name].find_one({
"type": "project"
})
output.append(project_doc)
return Response(
status=200,
body=self.resource.encode(output),
content_type="application/json"
)


class AvalonProjectEndpoint(_RestApiEndpoint):
async def get(self, project_name) -> Response:
project_doc = self.dbcon.database[project_name].find_one({
"type": "project"
})
if project_doc:
return Response(
status=200,
body=self.resource.encode(project_doc),
content_type="application/json"
)
return Response(
status=404,
reason="Project name {} not found".format(project_name)
)


class AvalonAssetsEndpoint(_RestApiEndpoint):
async def get(self, project_name) -> Response:
asset_docs = list(self.dbcon.database[project_name].find({
"type": "asset"
}))
return Response(
status=200,
body=self.resource.encode(asset_docs),
content_type="application/json"
)


class AvalonAssetEndpoint(_RestApiEndpoint):
async def get(self, project_name, asset_name) -> Response:
asset_doc = self.dbcon.database[project_name].find_one({
"type": "asset",
"name": asset_name
})
if asset_doc:
return Response(
status=200,
body=self.resource.encode(asset_doc),
content_type="application/json"
)
return Response(
status=404,
reason="Asset name {} not found in project {}".format(
asset_name, project_name
)
)


class AvalonRestApiResource:
def __init__(self, avalon_module, server_manager):
self.module = avalon_module
self.server_manager = server_manager

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dbcon = AvalonMongoDB()
self.dbcon.install()

@RestApi.route("/projects/<project_name>", url_prefix="/avalon", methods="GET")
def get_project(self, request):
project_name = request.url_data["project_name"]
if not project_name:
output = {}
for project_name in self.dbcon.tables():
project = self.dbcon[project_name].find_one({
"type": "project"
})
output[project_name] = project

return CallbackResult(data=self.result_to_json(output))

project = self.dbcon[project_name].find_one({"type": "project"})

if project:
return CallbackResult(data=self.result_to_json(project))

abort(404, "Project \"{}\" was not found in database".format(
project_name
))

@RestApi.route("/projects/<project_name>/assets/<asset>", url_prefix="/avalon", methods="GET")
def get_assets(self, request):
_project_name = request.url_data["project_name"]
_asset = request.url_data["asset"]

if not self.dbcon.exist_table(_project_name):
abort(404, "Project \"{}\" was not found in database".format(
_project_name
))

if not _asset:
assets = self.dbcon[_project_name].find({"type": "asset"})
output = self.result_to_json(assets)
return CallbackResult(data=output)

# identificator can be specified with url query (default is `name`)
identificator = request.query.get("identificator", "name")

asset = self.dbcon[_project_name].find_one({
"type": "asset",
identificator: _asset
})
if asset:
id = asset["_id"]
asset["_id"] = str(id)
return asset

abort(404, "Asset \"{}\" with {} was not found in project {}".format(
_asset, identificator, _project_name
))

def result_to_json(self, result):
""" Converts result of MongoDB query to dict without $oid (ObjectId)
keys with help of regex matching.

..note:
This will convert object type entries similar to ObjectId.
"""
bson_json = bson.json_util.dumps(result)
# Replace "{$oid: "{entity id}"}" with "{entity id}"
regex1 = '(?P<id>{\"\$oid\": \"[^\"]+\"})'
regex2 = '{\"\$oid\": (?P<id>\"[^\"]+\")}'
for value in re.findall(regex1, bson_json):
for substr in re.findall(regex2, value):
bson_json = bson_json.replace(value, substr)

return json.loads(bson_json)
self.prefix = "/avalon"

self.endpoint_defs = (
(
"GET",
"/projects",
AvalonProjectsEndpoint(self)
),
(
"GET",
"/projects/{project_name}",
AvalonProjectEndpoint(self)
),
(
"GET",
"/projects/{project_name}/assets",
AvalonAssetsEndpoint(self)
),
(
"GET",
"/projects/{project_name}/assets/{asset_name}",
AvalonAssetEndpoint(self)
)
)

self.register()

def register(self):
for methods, url, endpoint in self.endpoint_defs:
final_url = self.prefix + url
self.server_manager.add_route(
methods, final_url, endpoint.dispatch
)

@staticmethod
def json_dump_handler(value):
if isinstance(value, datetime.datetime):
return value.isoformat()
if isinstance(value, ObjectId):
return str(value)
raise TypeError(value)

@classmethod
def encode(cls, data):
return json.dumps(
data,
indent=4,
default=cls.json_dump_handler
).encode("utf-8")
22 changes: 13 additions & 9 deletions pype/modules/muster/muster.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
import json
import appdirs
import requests
from .. import PypeModule, ITrayModule, IRestApi
from .. import (
PypeModule,
ITrayModule,
IWebServerRoutes
)


class MusterModule(PypeModule, ITrayModule, IRestApi):
class MusterModule(PypeModule, ITrayModule, IWebServerRoutes):
"""
Module handling Muster Render credentials. This will display dialog
asking for user credentials for Muster if not already specified.
Expand All @@ -28,6 +32,7 @@ def initialize(self, modules_settings):
# Tray attributes
self.widget_login = None
self.action_show_login = None
self.rest_api_obj = None

def get_global_environments(self):
return {
Expand Down Expand Up @@ -71,13 +76,12 @@ def tray_menu(self, parent):

parent.addMenu(menu)

def rest_api_initialization(self, rest_api_module):
"""Implementation of IRestApi interface."""
def api_show_login():
self.action_show_login.trigger()
rest_api_module.register_callback(
"/show_login", api_show_login, "muster", "post"
)
def webserver_initialization(self, server_manager):
"""Implementation of IWebServerRoutes interface."""
if self.tray_initialized:
from .rest_api import MusterModuleRestApi

self.rest_api_obj = MusterModuleRestApi(self, server_manager)

def load_credentials(self):
"""
Expand Down
Loading