opengamedata-api-utils 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 opengamedata
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.1
2
+ Name: opengamedata-api-utils
3
+ Version: 1.0.0
4
+ Summary: Package of utilities for server-side scripts in OpenGameData.
5
+ Author: Ryan Wilkinson, Glenn Palmer, Daus Husaini
6
+ Author-email: Luke Swanson <superscription58@gmail.com>
7
+ Project-URL: Homepage, https://github.com/opengamedata/opengamedata-api-utils
8
+ Project-URL: Bug Tracker, https://github.com/opengamedata/opengamedata-api-utils/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+
16
+ # opengamedata-server
17
+
18
+ Repository for server-side scripts in opengamedata. In particular, this is where we have code for the OGD APIs.
19
+
20
+ ## Getting Started
21
+
22
+ ### Hello World of Flask
23
+
24
+ Steps to run:
25
+ 1. Check out latest `opengamedata-server`.
26
+ 2. Run `pip install -r requirements.txt` to ensure you've got flask.
27
+ 3. Run `flask run`.
28
+ 4. Open localhost:5000 or localhost:5000/hello to see some really basic text output from the Flask server.
29
+
30
+ If Flask doesn't run, it's possible you'd need to first export FLASK_APP as an environment variable, set to "wsgi" (so in Bash, export FLASK_APP=wsgi).
31
+ However, the script is named wsgi.py specifically because Flask is supposed to auto-detect it. So if this issue ever did come up, please ping Luke so he can look into it.
32
+
33
+ ## APIs
34
+
35
+ Below is a listing of the current API calls available, in function format to indicate what the request parameters.
36
+ For each API, there is also an api path, with path parameters in angle bracket (<, >) format.
37
+ Lastly, at this point in time, the `<server_path>` is `https://fieldday-web.wcer.wisc.edu/opengamedata.wsgi`
38
+
39
+ ### Classroom API
40
+
41
+ ### Dashboard API
42
+
43
+ ### Hello API
44
+
45
+ #### Verify the API is alive
46
+
47
+ `<server_path>/hello`
48
+ `GET()`
49
+
50
+ - returns no value, and a success message
51
+
52
+ `POST()`
53
+
54
+ - returns no value, and a success message
55
+
56
+ `PUT()`
57
+
58
+ - returns no value, and a success message
59
+
60
+
61
+ ### Player API
62
+
63
+ ### Generate and save players
64
+
65
+ `<server_path>/player`
66
+ `GET()`
67
+
68
+ - returns an unused, randomized player name, or a null value and error message
69
+
70
+ `PUT(str player_id, str name = None)`
71
+
72
+ - Returns no value, and either a success or error message
73
+ ---
@@ -0,0 +1,58 @@
1
+ # opengamedata-server
2
+
3
+ Repository for server-side scripts in opengamedata. In particular, this is where we have code for the OGD APIs.
4
+
5
+ ## Getting Started
6
+
7
+ ### Hello World of Flask
8
+
9
+ Steps to run:
10
+ 1. Check out latest `opengamedata-server`.
11
+ 2. Run `pip install -r requirements.txt` to ensure you've got flask.
12
+ 3. Run `flask run`.
13
+ 4. Open localhost:5000 or localhost:5000/hello to see some really basic text output from the Flask server.
14
+
15
+ If Flask doesn't run, it's possible you'd need to first export FLASK_APP as an environment variable, set to "wsgi" (so in Bash, export FLASK_APP=wsgi).
16
+ However, the script is named wsgi.py specifically because Flask is supposed to auto-detect it. So if this issue ever did come up, please ping Luke so he can look into it.
17
+
18
+ ## APIs
19
+
20
+ Below is a listing of the current API calls available, in function format to indicate what the request parameters.
21
+ For each API, there is also an api path, with path parameters in angle bracket (<, >) format.
22
+ Lastly, at this point in time, the `<server_path>` is `https://fieldday-web.wcer.wisc.edu/opengamedata.wsgi`
23
+
24
+ ### Classroom API
25
+
26
+ ### Dashboard API
27
+
28
+ ### Hello API
29
+
30
+ #### Verify the API is alive
31
+
32
+ `<server_path>/hello`
33
+ `GET()`
34
+
35
+ - returns no value, and a success message
36
+
37
+ `POST()`
38
+
39
+ - returns no value, and a success message
40
+
41
+ `PUT()`
42
+
43
+ - returns no value, and a success message
44
+
45
+
46
+ ### Player API
47
+
48
+ ### Generate and save players
49
+
50
+ `<server_path>/player`
51
+ `GET()`
52
+
53
+ - returns an unused, randomized player name, or a null value and error message
54
+
55
+ `PUT(str player_id, str name = None)`
56
+
57
+ - Returns no value, and either a success or error message
58
+ ---
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 61.0", "wheel", "setuptools-git-versioning >= 1.13"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.setuptools-git-versioning]
6
+ enabled = true
7
+
8
+ [project]
9
+ name = "opengamedata-api-utils"
10
+ dynamic = ["version"]
11
+ authors = [
12
+ { name="Luke Swanson", email="superscription58@gmail.com" },
13
+ { name="Ryan Wilkinson" },
14
+ { name="Glenn Palmer" },
15
+ { name="Daus Husaini" }
16
+ ]
17
+ description = "Package of utilities for server-side scripts in OpenGameData."
18
+ readme = "README.md"
19
+ requires-python = ">=3.10"
20
+ classifiers = [
21
+ "Programming Language :: Python :: 3",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Operating System :: OS Independent",
24
+ ]
25
+
26
+ [project.urls]
27
+ "Homepage" = "https://github.com/opengamedata/opengamedata-api-utils"
28
+ "Bug Tracker" = "https://github.com/opengamedata/opengamedata-api-utils/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,9 @@
1
+ __all__ = [
2
+ "config",
3
+ "utils",
4
+ "schemas"
5
+ ]
6
+
7
+ from . import config
8
+ from . import utils
9
+ from . import schemas
@@ -0,0 +1,148 @@
1
+ """
2
+ ServerConfigSchema
3
+
4
+ Contains a Schema class for managing config data for server configurations.
5
+ """
6
+
7
+ # import standard libraries
8
+ import logging
9
+ from pathlib import Path
10
+ from typing import Any, Dict, List
11
+
12
+ # import 3rd-party libraries
13
+
14
+ # import OGD libraries
15
+ from ogd.core.schemas.Schema import Schema
16
+ from ogd.core.schemas.configs.data_sources.MySQLSourceSchema import MySQLSchema
17
+
18
+ # import local files
19
+
20
+ class ServerConfigSchema(Schema):
21
+ def __init__(self, name:str, all_elements:Dict[str, Any], logger:logging.Logger):
22
+ self._state_dbs : Dict[str, MySQLSchema]
23
+ self._ogd_core : Path
24
+ self._google_client_id : str
25
+ self._dbg_level : int
26
+ self._version : int
27
+
28
+ if "DB_CONFIG" in all_elements.keys():
29
+ self._data_src = ServerConfigSchema._parseDataSources(all_elements["DB_CONFIG"], logger=logger)
30
+ else:
31
+ self._data_src = {}
32
+ logger.warn(f"{name} config does not have a 'DB_CONFIG' element; defaulting to game_sources={self._data_src}", logging.WARN)
33
+ if "OGD_CORE_PATH" in all_elements.keys():
34
+ self._ogd_core = ServerConfigSchema._parseOGDPath(path=all_elements["OGD_CORE_PATH"], logger=logger)
35
+ else:
36
+ self._ogd_core = Path("./") / "opengamedata"
37
+ logger.warn(f"{name} config does not have a 'OGD_CORE_PATH' element; defaulting to ogd_core_path={self._ogd_core}", logging.WARN)
38
+ if "GOOGLE_CLIENT_ID" in all_elements.keys():
39
+ self._google_client_id = ServerConfigSchema._parseGoogleID(google_id=all_elements["GOOGLE_CLIENT_ID"], logger=logger)
40
+ else:
41
+ self._google_client_id = "UNKNOWN ID"
42
+ logger.warn(f"{name} config does not have a 'GOOGLE_CLIENT_ID' element; defaulting to google_client_id={self._google_client_id}", logging.WARN)
43
+ if "DEBUG_LEVEL" in all_elements.keys():
44
+ self._dbg_level = ServerConfigSchema._parseDebugLevel(all_elements["DEBUG_LEVEL"], logger=logger)
45
+ else:
46
+ self._dbg_level = logging.INFO
47
+ logger.warn(f"{name} config does not have a 'DEBUG_LEVEL' element; defaulting to dbg_level={self._dbg_level}", logging.WARN)
48
+ if "VER" in all_elements.keys():
49
+ self._version = ServerConfigSchema._parseVersion(all_elements["VER"], logger=logger)
50
+ else:
51
+ self._version = -1
52
+ logger.warn(f"{name} config does not have a 'VER' element; defaulting to version={self._version}", logging.WARN)
53
+
54
+ _used = {"DB_CONFIG", "OGD_CORE_PATH", "GOOGLE_CLIENT_ID", "DEBUG_LEVEL", "VER"}
55
+ _leftovers = { key : val for key,val in all_elements.items() if key not in _used }
56
+ super().__init__(name=name, other_elements=_leftovers)
57
+
58
+ @property
59
+ def StateDatabases(self) -> Dict[str, MySQLSchema]:
60
+ return self._state_dbs
61
+
62
+ @property
63
+ def OGDCore(self) -> Path:
64
+ return self._ogd_core
65
+
66
+ @property
67
+ def GoogleClientID(self) -> str:
68
+ return self._google_client_id
69
+
70
+ @property
71
+ def DebugLevel(self) -> int:
72
+ return self._dbg_level
73
+
74
+ @property
75
+ def Version(self) -> int:
76
+ return self._version
77
+
78
+ @property
79
+ def AsMarkdown(self) -> str:
80
+ ret_val : str
81
+
82
+ ret_val = f"{self.Name}"
83
+ return ret_val
84
+
85
+ @staticmethod
86
+ def _parseDataSources(sources, logger:logging.Logger) -> Dict[str, MySQLSchema]:
87
+ ret_val : Dict[str, MySQLSchema]
88
+ if isinstance(sources, dict):
89
+ ret_val = {}
90
+ for key,val in sources.items():
91
+ ret_val[key] = MySQLSchema(name=key, all_elements=val)
92
+ else:
93
+ ret_val = {}
94
+ logger.warn(f"Config data sources was unexpected type {type(sources)}, defaulting to empty dict: {ret_val}.", logging.WARN)
95
+ return ret_val
96
+
97
+ @staticmethod
98
+ def _parseOGDPath(path, logger:logging.Logger) -> Path:
99
+ ret_val : Path
100
+ if isinstance(path, str):
101
+ ret_val = Path(path)
102
+ else:
103
+ ret_val = Path("./") / "opengamedata"
104
+ logger.warn(f"Data Source DB type was unexpected type {type(path)}, defaulting to path={ret_val}.", logging.WARN)
105
+ return ret_val
106
+
107
+ @staticmethod
108
+ def _parseGoogleID(google_id, logger:logging.Logger) -> str:
109
+ ret_val : str
110
+ if isinstance(google_id, str):
111
+ ret_val = google_id
112
+ else:
113
+ ret_val = str(google_id)
114
+ logger.warn(f"Google Client ID type was unexpected type {type(google_id)}, defaulting to google_client_id=str({ret_val}).", logging.WARN)
115
+ return ret_val
116
+
117
+ @staticmethod
118
+ def _parseDebugLevel(level, logger:logging.Logger) -> int:
119
+ ret_val : int
120
+ if isinstance(level, str):
121
+ match level.upper():
122
+ case "ERROR":
123
+ ret_val = logging.ERROR
124
+ case "WARNING" | "WARN":
125
+ ret_val = logging.WARN
126
+ case "INFO":
127
+ ret_val = logging.INFO
128
+ case "DEBUG":
129
+ ret_val = logging.DEBUG
130
+ case _:
131
+ ret_val = logging.INFO
132
+ logger.warn(f"Config debug level had unexpected value {level}, defaulting to logging.INFO.", logging.WARN)
133
+ else:
134
+ ret_val = logging.INFO
135
+ logger.warn(f"Config debug level was unexpected type {type(level)}, defaulting to logging.INFO.", logging.WARN)
136
+ return ret_val
137
+
138
+ @staticmethod
139
+ def _parseVersion(version, logger:logging.Logger) -> int:
140
+ ret_val : int
141
+ if isinstance(version, int):
142
+ ret_val = version
143
+ elif isinstance(version, str):
144
+ ret_val = int(version)
145
+ else:
146
+ ret_val = int(str(version))
147
+ logger.warn(f"Config version was unexpected type {type(version)}, defaulting to int(str(version))={ret_val}.", logging.WARN)
148
+ return ret_val
@@ -0,0 +1,164 @@
1
+ """
2
+ APIResponse
3
+
4
+ Contains class for representing a response from an OGD API,
5
+ as well as utility enums used by the APIResponse class.
6
+ """
7
+
8
+ # import standard libraries
9
+ import json
10
+ from enum import IntEnum
11
+ from typing import Any, Dict
12
+
13
+ # import 3rd-party libraries
14
+
15
+ # import OGD libraries
16
+ import ogd.core.requests.RequestResult as RequestResult
17
+
18
+ # Import local files
19
+
20
+ class RESTType(IntEnum):
21
+ """Simple enumerated type to track type of a REST request.
22
+ """
23
+ GET = 1
24
+ POST = 2
25
+ PUT = 3
26
+
27
+ def __str__(self):
28
+ """Stringify function for RESTTypes.
29
+
30
+ :return: Simple string version of the name of a RESTType
31
+ :rtype: _type_
32
+ """
33
+ match self.value:
34
+ case RESTType.GET:
35
+ return "GET"
36
+ case RESTType.POST:
37
+ return "POST"
38
+ case RESTType.PUT:
39
+ return "PUT"
40
+ case _:
41
+ return "INVALID REST TYPE"
42
+
43
+ class ResponseStatus(IntEnum):
44
+ """Simple enumerated type to track the status of an API request result.
45
+ """
46
+ NONE = 1
47
+ SUCCESS = 200
48
+ ERR_REQ = 400
49
+ ERR_SRV = 500
50
+
51
+ def __str__(self):
52
+ """Stringify function for ResponseStatus objects.
53
+
54
+ :return: Simple string version of the name of a ResponseStatus
55
+ :rtype: _type_
56
+ """
57
+ match self.value:
58
+ case ResponseStatus.NONE:
59
+ return "NONE"
60
+ case ResponseStatus.SUCCESS:
61
+ return "SUCCESS"
62
+ case ResponseStatus.ERR_SRV:
63
+ return "SERVER ERROR"
64
+ case ResponseStatus.ERR_REQ:
65
+ return "REQUEST ERROR"
66
+ case _:
67
+ return "INVALID STATUS TYPE"
68
+
69
+ class APIResponse:
70
+ def __init__(self, req_type:RESTType, val:Any, msg:str, status:ResponseStatus):
71
+ self._type : RESTType = req_type
72
+ self._val : Dict[str, Any] = val
73
+ self._msg : str = msg
74
+ self._status : ResponseStatus = status
75
+
76
+ def __str__(self):
77
+ return f"{self.Type.name} request: {self.Status}\n{self.Message}\nValues: {self.Value}"
78
+
79
+ @staticmethod
80
+ def Default(req_type:RESTType):
81
+ return APIResponse(
82
+ req_type=req_type,
83
+ val=None,
84
+ msg="",
85
+ status=ResponseStatus.NONE
86
+ )
87
+
88
+ @staticmethod
89
+ def FromRequestResult(result:RequestResult.RequestResult, req_type:RESTType):
90
+ _status : ResponseStatus
91
+ if result.Status == RequestResult.ResultStatus.SUCCESS:
92
+ _status = ResponseStatus.SUCCESS
93
+ elif result.Status == RequestResult.ResultStatus.FAILURE:
94
+ _status = ResponseStatus.ERR_REQ
95
+ else:
96
+ _status = ResponseStatus.ERR_SRV
97
+ ret_val = APIResponse(req_type=req_type, val=None, msg=result.Message, status=_status)
98
+ return ret_val
99
+
100
+ @property
101
+ def Type(self) -> RESTType:
102
+ """Property for the type of REST request
103
+
104
+ :return: A RESTType representing the type of REST request
105
+ :rtype: _type_
106
+ """
107
+ return self._type
108
+
109
+ @property
110
+ def Value(self) -> Dict[str, Any]:
111
+ """Property for the value of the request result.
112
+
113
+ :return: Some value, of any type, returned from the request.
114
+ :rtype: Any
115
+ """
116
+ return self._val
117
+ @Value.setter
118
+ def Value(self, new_val:Dict[str, Any]):
119
+ self._val = new_val
120
+
121
+
122
+ @property
123
+ def Message(self) -> str:
124
+ """Property for the message associated with a request result.
125
+
126
+ :return: A string message giving details on the result of the request.
127
+ :rtype: str
128
+ """
129
+ return self._msg
130
+
131
+ @property
132
+ def Status(self) -> ResponseStatus:
133
+ """Property for the status of the request.
134
+
135
+ :return: A ResponseStatus indicating whether request is/was successful, incomplete, failed, etc.
136
+ :rtype: ResponseStatus
137
+ """
138
+ return self._status
139
+
140
+ @property
141
+ def AsDict(self):
142
+ return {
143
+ "type" : str(self._type),
144
+ "val" : json.dumps(self._val),
145
+ "msg" : self._msg,
146
+ "status" : str(self._status)
147
+ }
148
+
149
+ @property
150
+ def AsJSON(self):
151
+ return json.dumps(self.AsDict)
152
+
153
+ def RequestErrored(self, msg:str):
154
+ self._status = ResponseStatus.ERR_REQ
155
+ self._msg = f"ERROR: {msg}"
156
+
157
+ def ServerErrored(self, msg:str):
158
+ self._status = ResponseStatus.ERR_SRV
159
+ self._msg = f"SERVER ERROR: {msg}"
160
+
161
+ def RequestSucceeded(self, msg:str, val:Any):
162
+ self._status = ResponseStatus.SUCCESS
163
+ self._msg = f"SUCCESS: {msg}"
164
+ self._val = val
@@ -0,0 +1,92 @@
1
+ """
2
+ APIUtils
3
+
4
+ Contains general utility functions for common tasks when setting up our flask/flask-restful API functions.
5
+ In particular, has functions to assist in parsing certain kinds of data, and for generating OGD-core objects.
6
+ """
7
+
8
+ # import standard libraries
9
+ import json
10
+ import os
11
+ from typing import Any, List, Optional
12
+
13
+ # import 3rd-party libraries
14
+ from flask import current_app
15
+
16
+ # import OGD libraries
17
+ from ogd.core.interfaces.DataInterface import DataInterface
18
+ from ogd.core.interfaces.MySQLInterface import MySQLInterface
19
+ from ogd.core.interfaces.BigQueryInterface import BigQueryInterface
20
+ from ogd.core.schemas.configs.ConfigSchema import ConfigSchema
21
+ from ogd.core.schemas.configs.GameSourceSchema import GameSourceSchema
22
+
23
+ # import local files
24
+
25
+ def parse_list(list_str:str) -> Optional[List[Any]]:
26
+ """Simple utility to parse a string containing a bracketed list into a Python list.
27
+ Returns None if the list was empty
28
+
29
+ :param list_str: _description_
30
+ :type list_str: str
31
+ :return: A list parsed from the input string, or None if the string list was invalid or empty.
32
+ :rtype: Union[List[Any], None]
33
+ """
34
+ ret_val : Optional[List[Any]] = None
35
+ try:
36
+ ret_val = json.loads(list_str)
37
+ except json.decoder.JSONDecodeError as e:
38
+ current_app.logger.warn(f"Could not parse '{list_str}' as a list, format was not valid!\nGot Error {e}")
39
+ else:
40
+ if ret_val is not None and len(ret_val) == 0:
41
+ # If we had empty list, just treat as null.
42
+ ret_val = None
43
+ return ret_val
44
+
45
+ def gen_interface(game_id, core_config:ConfigSchema) -> Optional[DataInterface]:
46
+ """Utility to set up an Interface object for use by the API, given a game_id.
47
+
48
+ :param game_id: _description_
49
+ :type game_id: _type_
50
+ :return: _description_
51
+ :rtype: _type_
52
+ """
53
+ ret_val = None
54
+
55
+ _game_source : GameSourceSchema = core_config.GameSourceMap.get(game_id, GameSourceSchema.EmptySchema())
56
+
57
+ if _game_source.Source is not None:
58
+ # set up interface and request
59
+ if _game_source.Source.Type.upper() == "MYSQL":
60
+ ret_val = MySQLInterface(game_id, config=_game_source, fail_fast=False)
61
+ current_app.logger.info(f"Using MySQLInterface for {game_id}")
62
+ elif _game_source.Source.Type.upper() == "BIGQUERY":
63
+ current_app.logger.info(f"Generating BigQueryInterface for {game_id}, from directory {os.getcwd()}...")
64
+ ret_val = BigQueryInterface(game_id=game_id, config=_game_source, fail_fast=False)
65
+ current_app.logger.info("Done")
66
+ else:
67
+ ret_val = MySQLInterface(game_id, config=_game_source, fail_fast=False)
68
+ current_app.logger.warning(f"Could not find a valid interface for {game_id}, defaulting to MySQL!")
69
+ return ret_val
70
+
71
+ # def gen_coding_interface(game_id) -> Optional[CodingInterface]:
72
+ # """Utility to set up an Interface object for use by the API, given a game_id.
73
+
74
+ # :param game_id: _description_
75
+ # :type game_id: _type_
76
+ # :return: _description_
77
+ # :rtype: _type_
78
+ # """
79
+ # ret_val = None
80
+
81
+ # _core_config = ConfigSchema(name="Core Config", all_elements=core_settings)
82
+ # _game_source : GameSourceSchema = _core_config.GameSourceMap.get(game_id, GameSourceSchema.EmptySchema())
83
+
84
+ # if _game_source.Source is not None:
85
+ # # set up interface and request
86
+ # if _game_source.Source.Type == "BigQuery":
87
+ # ret_val = BigQueryCodingInterface(game_id=game_id, config=_core_config)
88
+ # current_app.logger.info(f"Using BigQueryCodingInterface for {game_id}")
89
+ # else:
90
+ # ret_val = BigQueryCodingInterface(game_id=game_id, config=_core_config)
91
+ # current_app.logger.warning(f"Could not find a valid interface for {game_id}, defaulting to BigQuery!")
92
+ # return ret_val
@@ -0,0 +1,73 @@
1
+ """
2
+ HelloAPI
3
+
4
+ Contains the HelloAPI class, which we register to all API apps as a way to test that the app is active.
5
+ """
6
+
7
+ # import libraries
8
+
9
+ # import 3rd-party libraries
10
+ from flask import Flask
11
+ from flask_restful import Resource, Api
12
+
13
+ # import OGD libraries
14
+ from ogd.apis.utils.APIResponse import APIResponse, RESTType, ResponseStatus
15
+
16
+ # import locals
17
+
18
+ class HelloAPI:
19
+ @staticmethod
20
+ def register(app:Flask):
21
+ api = Api(app)
22
+ api.add_resource(HelloAPI.Hello, '/hello')
23
+ api.add_resource(HelloAPI.ParamHello, '/p_hello/<name>')
24
+
25
+ class Hello(Resource):
26
+ def get(self):
27
+ ret_val = APIResponse(
28
+ req_type = RESTType.GET,
29
+ val = None,
30
+ msg = "Hello! You GETted successfully!",
31
+ status = ResponseStatus.SUCCESS)
32
+ return ret_val.AsDict
33
+
34
+ def post(self):
35
+ ret_val = APIResponse(
36
+ req_type = RESTType.POST,
37
+ val = None,
38
+ msg = "Hello! You POSTed successfully!",
39
+ status = ResponseStatus.SUCCESS)
40
+ return ret_val.AsDict
41
+
42
+ def put(self):
43
+ ret_val = APIResponse(
44
+ req_type = RESTType.PUT,
45
+ val = None,
46
+ msg = "Hello! You PUTted successfully!",
47
+ status = ResponseStatus.SUCCESS)
48
+ return ret_val.AsDict
49
+
50
+ class ParamHello(Resource):
51
+ def get(self, name):
52
+ ret_val = APIResponse(
53
+ req_type = RESTType.GET,
54
+ val = None,
55
+ msg = f"Hello {name}! You GETted successfully!",
56
+ status = ResponseStatus.SUCCESS)
57
+ return ret_val.AsDict
58
+
59
+ def post(self, name):
60
+ ret_val = APIResponse(
61
+ req_type = RESTType.POST,
62
+ val = None,
63
+ msg = f"Hello {name}! You POSTed successfully!",
64
+ status = ResponseStatus.SUCCESS)
65
+ return ret_val.AsDict
66
+
67
+ def put(self, name):
68
+ ret_val = APIResponse(
69
+ req_type = RESTType.PUT,
70
+ val = None,
71
+ msg = f"Hello {name}! You PUTted successfully!",
72
+ status = ResponseStatus.SUCCESS)
73
+ return ret_val.AsDict
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.1
2
+ Name: opengamedata-api-utils
3
+ Version: 1.0.0
4
+ Summary: Package of utilities for server-side scripts in OpenGameData.
5
+ Author: Ryan Wilkinson, Glenn Palmer, Daus Husaini
6
+ Author-email: Luke Swanson <superscription58@gmail.com>
7
+ Project-URL: Homepage, https://github.com/opengamedata/opengamedata-api-utils
8
+ Project-URL: Bug Tracker, https://github.com/opengamedata/opengamedata-api-utils/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+
16
+ # opengamedata-server
17
+
18
+ Repository for server-side scripts in opengamedata. In particular, this is where we have code for the OGD APIs.
19
+
20
+ ## Getting Started
21
+
22
+ ### Hello World of Flask
23
+
24
+ Steps to run:
25
+ 1. Check out latest `opengamedata-server`.
26
+ 2. Run `pip install -r requirements.txt` to ensure you've got flask.
27
+ 3. Run `flask run`.
28
+ 4. Open localhost:5000 or localhost:5000/hello to see some really basic text output from the Flask server.
29
+
30
+ If Flask doesn't run, it's possible you'd need to first export FLASK_APP as an environment variable, set to "wsgi" (so in Bash, export FLASK_APP=wsgi).
31
+ However, the script is named wsgi.py specifically because Flask is supposed to auto-detect it. So if this issue ever did come up, please ping Luke so he can look into it.
32
+
33
+ ## APIs
34
+
35
+ Below is a listing of the current API calls available, in function format to indicate what the request parameters.
36
+ For each API, there is also an api path, with path parameters in angle bracket (<, >) format.
37
+ Lastly, at this point in time, the `<server_path>` is `https://fieldday-web.wcer.wisc.edu/opengamedata.wsgi`
38
+
39
+ ### Classroom API
40
+
41
+ ### Dashboard API
42
+
43
+ ### Hello API
44
+
45
+ #### Verify the API is alive
46
+
47
+ `<server_path>/hello`
48
+ `GET()`
49
+
50
+ - returns no value, and a success message
51
+
52
+ `POST()`
53
+
54
+ - returns no value, and a success message
55
+
56
+ `PUT()`
57
+
58
+ - returns no value, and a success message
59
+
60
+
61
+ ### Player API
62
+
63
+ ### Generate and save players
64
+
65
+ `<server_path>/player`
66
+ `GET()`
67
+
68
+ - returns an unused, randomized player name, or a null value and error message
69
+
70
+ `PUT(str player_id, str name = None)`
71
+
72
+ - Returns no value, and either a success or error message
73
+ ---
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/ogd/apis/__init__.py
5
+ src/ogd/apis/schemas/ServerConfigSchema.py
6
+ src/ogd/apis/schemas/__init__.py
7
+ src/ogd/apis/utils/APIResponse.py
8
+ src/ogd/apis/utils/APIUtils.py
9
+ src/ogd/apis/utils/HelloAPI.py
10
+ src/ogd/apis/utils/__init__.py
11
+ src/opengamedata_api_utils.egg-info/PKG-INFO
12
+ src/opengamedata_api_utils.egg-info/SOURCES.txt
13
+ src/opengamedata_api_utils.egg-info/dependency_links.txt
14
+ src/opengamedata_api_utils.egg-info/top_level.txt