aboutsummaryrefslogtreecommitdiffstats
path: root/pysite/views/api
diff options
context:
space:
mode:
Diffstat (limited to 'pysite/views/api')
-rw-r--r--pysite/views/api/bot/bigbrother.py118
-rw-r--r--pysite/views/api/bot/off_topic_names.py2
-rw-r--r--pysite/views/api/robots_txt.py15
-rw-r--r--pysite/views/api/sitemap_xml.py11
4 files changed, 145 insertions, 1 deletions
diff --git a/pysite/views/api/bot/bigbrother.py b/pysite/views/api/bot/bigbrother.py
new file mode 100644
index 00000000..89697811
--- /dev/null
+++ b/pysite/views/api/bot/bigbrother.py
@@ -0,0 +1,118 @@
+import json
+
+from flask import jsonify
+from schema import And, Optional, Schema
+
+from pysite.base_route import APIView
+from pysite.constants import ValidationTypes
+from pysite.decorators import api_key, api_params
+from pysite.mixins import DBMixin
+
+
+GET_SCHEMA = Schema({
+ # This is passed as a GET parameter, so it has to be a string
+ Optional('user_id'): And(str, str.isnumeric, error="`user_id` must be a numeric string")
+})
+
+POST_SCHEMA = Schema({
+ 'user_id': And(str, str.isnumeric, error="`user_id` must be a numeric string"),
+ 'channel_id': And(str, str.isnumeric, error="`channel_id` must be a numeric string")
+})
+
+DELETE_SCHEMA = Schema({
+ 'user_id': And(str, str.isnumeric, error="`user_id` must be a numeric string")
+})
+
+
+NOT_A_NUMBER_JSON = json.dumps({
+ 'error_message': "The given `user_id` parameter is not a valid number"
+})
+NOT_FOUND_JSON = json.dumps({
+ 'error_message': "No entry for the requested user ID could be found."
+})
+
+
+class BigBrotherView(APIView, DBMixin):
+ path = '/bot/bigbrother'
+ name = 'bot.bigbrother'
+ table_name = 'watched_users'
+
+ @api_key
+ @api_params(schema=GET_SCHEMA, validation_type=ValidationTypes.params)
+ def get(self, params):
+ """
+ Without query parameters, returns a list of all monitored users.
+ A parameter `user_id` can be specified to return a single entry,
+ or a dictionary with the string field 'error_message' that tells why it failed.
+
+ If the returned status is 200, has got either a list of entries
+ or a single object (see above).
+
+ If the returned status is 400, the `user_id` parameter was incorrectly specified.
+ If the returned status is 404, the given `user_id` could not be found.
+ See the 'error_message' field in the JSON response for more information.
+
+ The user ID must be provided as query parameter.
+ API key must be provided as header.
+ """
+
+ user_id = params.get('user_id')
+ if user_id is not None:
+ data = self.db.get(self.table_name, user_id)
+ if data is None:
+ return NOT_FOUND_JSON, 404
+ return jsonify(data)
+
+ else:
+ data = self.db.pluck(self.table_name, ('user_id', 'channel_id')) or []
+ return jsonify(data)
+
+ @api_key
+ @api_params(schema=POST_SCHEMA, validation_type=ValidationTypes.json)
+ def post(self, data):
+ """
+ Adds a new entry to the database.
+ Entries take the following form:
+ {
+ "user_id": ..., # The user ID of the user being monitored, as a string.
+ "channel_id": ... # The channel ID that the user's messages will be relayed to, as a string.
+ }
+
+ If an entry for the given `user_id` already exists, it will be updated with the new channel ID.
+
+ Returns 204 (ok, empty response) on success.
+
+ Data must be provided as JSON.
+ API key must be provided as header.
+ """
+
+ self.db.insert(
+ self.table_name,
+ {
+ 'user_id': data['user_id'],
+ 'channel_id': data['channel_id']
+ },
+ conflict='update'
+ )
+
+ return '', 204
+
+ @api_key
+ @api_params(schema=DELETE_SCHEMA, validation_type=ValidationTypes.params)
+ def delete(self, params):
+ """
+ Removes an entry for the given `user_id`.
+
+ Returns 204 (ok, empty response) on success.
+ Returns 400 if the given `user_id` is invalid.
+
+ The user ID must be provided as query parameter.
+ API key must be provided as header.
+ """
+
+ self.db.delete(
+ self.table_name,
+ params['user_id']
+ )
+
+ return '', 204
diff --git a/pysite/views/api/bot/off_topic_names.py b/pysite/views/api/bot/off_topic_names.py
index e0871067..f353ab02 100644
--- a/pysite/views/api/bot/off_topic_names.py
+++ b/pysite/views/api/bot/off_topic_names.py
@@ -13,7 +13,7 @@ POST_SCHEMA = Schema({
'name': And(
str,
len,
- lambda name: all(c.isalpha() or c == '-' for c in name),
+ lambda name: all(c.isalnum() or c == '-' for c in name),
str.islower,
lambda name: len(name) <= 96,
error=(
diff --git a/pysite/views/api/robots_txt.py b/pysite/views/api/robots_txt.py
new file mode 100644
index 00000000..d4406d54
--- /dev/null
+++ b/pysite/views/api/robots_txt.py
@@ -0,0 +1,15 @@
+from flask import Response, url_for
+
+from pysite.base_route import RouteView
+
+
+class RobotsTXT(RouteView):
+ path = "/robots.txt"
+ name = "robots_txt"
+
+ def get(self):
+ return Response(
+ self.render(
+ "robots.txt", sitemap_url=url_for("api.sitemap_xml", _external=True), rules={"*": ["/"]}
+ ), content_type="text/plain"
+ )
diff --git a/pysite/views/api/sitemap_xml.py b/pysite/views/api/sitemap_xml.py
new file mode 100644
index 00000000..26a786b0
--- /dev/null
+++ b/pysite/views/api/sitemap_xml.py
@@ -0,0 +1,11 @@
+from flask import Response
+
+from pysite.base_route import RouteView
+
+
+class SitemapXML(RouteView):
+ path = "/sitemap.xml"
+ name = "sitemap_xml"
+
+ def get(self):
+ return Response(self.render("sitemap.xml", urls=[]), content_type="application/xml")