Begin markdown docs

This commit is contained in:
Tanner Collin 2021-11-28 05:10:42 +00:00
parent 42b878abbf
commit 5e2454243b
7 changed files with 121 additions and 1198 deletions

View File

@ -0,0 +1,50 @@
# Spaceport API
The current API URL is: https://api.my.protospace.ca/
JSON is returned by all API responses including errors and HTTP response status
codes are to designate success and failure.
Request bodies can be JSON or form data.
All API routes require a trailing slash. This is a Django default and you'll get
a 301 redirect if you forget it.
## Authentication
Most API routes require authentication with a token. The token is returned on
registration and login. The token needs to be placed in the `Authorization`
request header like this: `Token <token>`.
**Example**
Login request:
```
$ curl -d 'username=tanner.collin' -d 'password=supersecret' 'https://my.protospace.ca/rest-auth/login/'
```
Login response:
```
{"key":"1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444"}
```
Add the following header to requests:
```
Authorization: Token 1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444
```
/user/ request:
```
curl -H 'Authorization: Token 1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444' 'https://my.protospace.ca/user/'
```
## API Routes
API routes are not documented. They used to be but the utility for how much
effort it took was not worth it.
Use your browser's network inspector to learn how the API works.

View File

@ -1,994 +0,0 @@
API
===
.. contents:: :depth: 3
User
----
Registration
++++++++++++
.. http:post:: /registration/
Register an account on Spaceport. Only works from Protospace's IP addresses.
:json first_name:
:json last_name:
:json username: Should be ``first.last``
:json password1:
:json password2:
:json email:
:json boolean existing_member: If ``true``, will link old portal objects based
on email match.
:json bypass_code: allows them to register from outside Protospace
**Example response**:
.. sourcecode:: json
{"key":"1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444"}
Login
+++++
.. http:post:: /rest-auth/login/
Log in with username and password, responds with auth token.
Put the token in the ``Authorization`` HTTP header like ``Token <token>`` to
authenticate.
:json username:
:json password:
**Example request**:
.. sourcecode:: bash
$ curl \
-d '{"username":"tanner.tester", "password":"supersecret"}' \
-H "Content-Type: application/json" \
-X POST \
http://api.spaceport.dns.t0.vc/rest-auth/login/
**Example response**:
.. sourcecode:: json
{"key":"1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444"}
Full User
+++++++++
.. http:get:: /user/
Retrieve an object with complete user data.
:requestheader Authorization: ``Token <token>``
**Example request**:
.. sourcecode:: bash
$ curl \
-H "Authorization: Token 1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444" \
https://api.spaceport.dns.t0.vc/user/
**Example response**:
.. sourcecode:: json
{
"id": 113,
"username": "tanner.tester",
"member": {
"id": 1685,
"status": "Current",
"email": "text",
"phone": "text",
"street_address": "text",
"city": "text",
"postal_code": "text",
"old_email": "text",
"photo_large": "uuid.jpg",
"photo_medium": "uuid.jpg",
"photo_small": "uuid.jpg",
"member_forms": "uuid.pdf",
"set_details": true,
"first_name": "Tanner",
"last_name": "Collin",
"preferred_name": "Tanner",
"emergency_contact_name": "text",
"emergency_contact_phone": "text",
"birthdate": null,
"is_minor": false,
"guardian_name": "",
"public_bio": "",
"private_notes": "",
"is_director": false,
"is_staff": true,
"is_instructor": false,
"expire_date": "2020-01-23",
"current_start_date": "2016-08-23",
"application_date": "2016-08-23",
"vetted_date": "2016-09-27",
"paused_date": null,
"monthly_fees": 50,
"user": 113
},
"transactions": [
{
"id": 31783,
"account_type": "PayPal",
"info_source": "PayPal IPN",
"member_name": "Tanner Collin",
"date": "2019-12-22",
"member_id": 1685,
"amount": "50.00",
"reference_number": "text",
"memo": "text",
"number_of_membership_months": null,
"payment_method": null,
"category": "Memberships:PayPal Payments",
"user": 113,
"recorder": null
}
],
"cards": [
{
"id": 392,
"member_id": 1685,
"card_number": "text",
"notes": "Tanner Collin",
"last_seen_at": "2020-01-20",
"active_status": "card_active",
"user": 113
}
],
"training": [
{
"id": 971,
"session": {
"id": 11073,
"student_count": 20,
"course_name": "Metal: Metal Cutting &amp; Manual Lathe",
"instructor_name": "John W",
"datetime": "2016-09-17T16:00:00Z",
"course": 281,
"is_cancelled": false,
"old_instructor": "John W",
"cost": "10.00",
"max_students": null,
"instructor": null
},
"member_id": 1685,
"attendance_status": "Confirmed",
"sign_up_date": null,
"paid_date": null
}
],
"is_staff": true
}
:json is_staff: Set in Django's admin panel. You'll need to set this for the
first user so that you can assign more admins.
:json member.is_staff: Set by directors / staff in UI.
Change Password
+++++++++++++++
.. http:post:: /password/change/
:json old_password:
:json password1:
:json password2:
**Example response**:
.. sourcecode:: json
{"detail":"New password has been saved."}
Reset Password
++++++++++++++
.. http:post:: /password/reset/
:json email:
**Example response**:
.. sourcecode:: json
{"detail":"Password reset e-mail has been sent."}
Confirm Reset
+++++++++++++
.. http:post:: /password/reset/confirm/
The uid and token are found in the email message:
``/password/reset/confirm/{uid}/{token}/``
:json uid:
:json token:
:json new_password1:
:json new_password2:
**Example response**:
.. sourcecode:: json
{"detail":"Password has been reset with the new password."}
Members
-------
Member Details
++++++++++++++
.. http:get:: /members/(id)/
Retrieve an object with member details. Users can only view themselves,
admins can view anyone.
:param id:
:requestheader Authorization: ``Token <token>``
**Example request**:
.. sourcecode:: bash
$ curl \
-H "Authorization: Token 1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444" \
https://api.spaceport.dns.t0.vc/members/1685/
**Example response**:
.. sourcecode:: json
{
"id": 1685,
"status": "Current",
"email": "text",
"phone": "text",
"street_address": "text",
"city": "text",
"postal_code": "text",
"old_email": "text",
"photo_large": "uuid.jpg",
"photo_medium": "uuid.jpg",
"photo_small": "uuid.jpg",
"member_forms": "uuid.pdf",
"set_details": true,
"first_name": "Tanner",
"last_name": "Collin",
"preferred_name": "Tanner",
"emergency_contact_name": "text",
"emergency_contact_phone": "text",
"birthdate": null,
"is_minor": false,
"guardian_name": "",
"public_bio": "",
"private_notes": "",
"is_director": false,
"is_staff": false,
"is_instructor": false,
"expire_date": "2020-01-23",
"current_start_date": "2016-08-23",
"application_date": "2016-08-23",
"vetted_date": "2016-09-27",
"paused_date": null,
"monthly_fees": 50,
"user": 113
}
:json member.old_email: From old portal import, used to claim member when
registering.
:json \*.member_id: From old portal import, used as a hint to link the
object to users when they claim their old member.
:json photo\_\*: Should be served by nginx on the ``static`` subdomain. Refers
to photo filenames in the ``apiserver/data/static`` directory.
:json member_forms: Should be served by nginx on the ``static`` subdomain.
:json status: Derived by subtracting today's date from expire_date. More
than one month: Prepaid, less than one month: Current, less than one
month behind: Due, more than one month behind: Overdue. Members more
than three months behind are paused. Value stored to make searching
faster.
:json expire_date: Derived by summing all member transaction's
number_of_membership_months and adding to member's current_start_date.
Value stored to make searching faster.
.. http:post:: /members/
Not allowed. Object is created upon registration.
Edit Member Details
+++++++++++++++++++
.. http:patch:: /members/(id)/
Set member details.
Member PDF forms will automatically be regenerated on any change.
**Users**
Can only set certain fields of their own member.
:form photo: A member photo that will be turned into different sizes and
referred to by photo_large, photo_medium, photo_small.
:json email:
:json phone:
:json street_address:
:json city:
:json postal_code:
:json boolean set_details: Set true if they've filled out the new member
form on sign up so the UI stops showing it.
:json preferred_name: What's shown throughout the UI.
:json emergency_contact_name: optional
:json emergency_contact_phone: optional
:json birthdate: optional, YYYY-MM-DD
:json boolean is_minor:
:json guardian_name: optional
:json public_bio: optional
:json private_notes: optional
**Admins**
Can modify any member. Above fields, plus:
:json first_name:
:json last_name:
:json boolean is_instructor: Able to create and edit courses and sessions.
:json application_date: When they applied to Protospace, YYYY-MM-DD.
:json current_start_date: When to start counting their membership dues from.
Would only differ from application_date for accounting reasons, YYYY-MM-DD.
:json vetted_date: YYYY-MM-DD
:json monthly_fees: used to match PayPal transactions
:requestheader Authorization: ``Token <token>``
**Response**
Same as GET.
.. http:put:: /members/(id)/
Same as PATCH but requires all fields present.
Pausing / Unpausing Member
++++++++++++++++++++++++++
.. http:post:: /members/(id)/pause/
/members/(id)/unpause/
Pause or unpause a membership. Can only be done by admins.
Pausing a member sets their paused_date to today. Their cards aren't sent to
the door controller. Their expire_date and status won't be evaluated daily
any longer.
Unpausing a member sets their current_start_date to their paused_date. Their
paused_date is then set to null. They will be Due. Their active cards will
begin working again.
:param id:
:requestheader Authorization: ``Token <token>``
**Response**
:status 200:
Search
------
Searching
+++++++++
.. http:post:: /search/
Perform a search for members' names.
Exact prefix matches are returned first, then exact substring matches, then
fuzzy matches.
POST is used because our auth header causes a pre-flight request. These
can't be cached if the URL keeps changing like with query params. Using the
request body for the query prevents an OPTIONS request per keystroke.
Designed to be fast enough for incremental search.
An empty search returns the most recently vetted members.
:json q: The search query.
:json int seq: An integer that gets returned with the search results.
Useful to prevent responses that arrive out-of-order from being
displayed as search results. ``event.timeStamp()`` is a good value to use.
:requestheader Authorization: ``Token <token>``
**Example response**:
.. sourcecode:: json
{
"seq": 12345,
"results": [
{
"member": {
"id": 1685,
"preferred_name": "Tanner",
"last_name": "Collin",
"status": "Current",
"current_start_date": "2016-08-23",
"photo_small": "uuid.jpg",
"photo_large": "uuid.jpg"
}
},
{
"member": {
"id": 1993,
"preferred_name": "Tanner",
"last_name": "text",
"status": "Former Member",
"current_start_date": null,
"photo_small": null,
"photo_large": null
}
}
]
}
Search Result
+++++++++++++
.. http:get:: /search/(id)/
Returns a specific search result. Users can see a partial member object. Admins can see the full member, cards, and transactions.
:param id:
:requestheader Authorization: ``Token <token>``
**Example user response**:
.. sourcecode:: json
{
"member": {
"id": 1685,
"preferred_name": "Tanner",
"last_name": "Collin",
"status": "Current",
"current_start_date": "2016-08-23",
"photo_small": "uuid.jpg",
"photo_large": "uuid.jpg"
}
}
**Example admin response**:
Truncated.
.. sourcecode:: json
{
"member": {},
"cards": [],
"transactions": [],
}
Transactions
------------
Transaction Details
+++++++++++++++++++
.. http:get:: /transactions/(id)/
Retrieve a transaction. Users can only view their own. Admins can view
anyone's.
:param id:
:requestheader Authorization: ``Token <token>``
**Example response**:
.. sourcecode:: json
{
"id": 40720,
"account_type": "PayPal",
"info_source": "PayPal IPN",
"member_id": 1685,
"member_name": "Tanner Collin",
"date": "2020-01-30",
"report_type": null,
"amount": "100.00",
"reference_number": "234236326",
"memo": "1685, text, email, etc",
"number_of_membership_months": 2,
"payment_method": "instant",
"category": "Memberships:PayPal Payments",
"paypal_txn_id": "234236326",
"paypal_payer_id": "123ABCDEFGHIJ",
"report_memo": null,
"user": 2,
"recorder": null
}
Reported Transactions
+++++++++++++++++++++
.. http:get:: /transactions/
Retrieve a list of reported transactions. Admins only.
Reported transactions are one with a report_type not null.
:requestheader Authorization: ``Token <token>``
**Example response**
Truncated.
.. sourcecode:: json
{
"count": 6,
"next": null,
"previous": null,
"results": [
{
"id": 40715,
"etc": "...",
},
{
"id": 40716,
"etc": "...",
},
{
"id": 40717,
"etc": "...",
}
]
}
Create Transaction
++++++++++++++++++
.. http:post:: /transactions/
Add a transaction to a member. Admins only.
:json date: YYYY-MM-DD
:json int member_id: Which member the transaction belongs to.
:json decimal amount: Positive is money going to Protospace, XX.XX.
:json account_type: One of: ``Interac``, ``TD Chequing``, ``Dream Pmt``,
``PayPal``, ``Square Pmt``, ``Member``, ``Clearing``, ``Cash``
:json info_source: One of: ``Web``, ``DB Edit``, ``System``, ``Receipt or Stmt``, ``Quicken
Import``, ``PayPal IPN``, ``Auto``, ``Nexus DB Bulk``, ``IPN Trigger``,
``Intranet Receipt``, ``Automatic``, ``Manual``
:json number_of_membership_months: Used when calculating member status and
expire date, optional.
:json reference_number: optional
:json memo: optional
:json payment_method: optional
:json category: optional
:json report_type: One of: ``null``, ``Unmatched Member``, ``Unmatched Purchase``,
``User Flagged``
:json report_memo: The reason for the report, optional.
:requestheader Authorization: ``Token <token>``
**Response**
Same as GET.
Edit Transaction
++++++++++++++++++
.. http:patch:: /transactions/(id)
Same fields as POST. Admins only.
:param id: The transaction's ID.
:requestheader Authorization: ``Token <token>``
.. http:put:: /transactions/(id)/
Same as PATCH but requires all fields present.
Report Transaction
++++++++++++++++++
.. http:post:: /transactions/(id)/report/
Allows users to report their own transactions for review.
``report_type`` will automatically be set to ``User Flagged``.
:param id: The transaction's ID.
:json report_memo: The reason for the report, required.
:requestheader Authorization: ``Token <token>``
**Response**
:status 200:
Courses
-------
.. http:get:: /courses/
List of all courses, ordered by which has most upcoming session.
Truncated.
.. sourcecode:: json
{
"count": 59,
"next": null,
"previous": null,
"results": [
{
"id": 261,
"name": "Woodworking Tools 1: Intro to Saws"
},
{
"id": 321,
"name": "Laser: Trotec Course"
}
]
}
.. http:get:: /courses/(id)/
:param id: The course's ID.
.. sourcecode:: json
{
"id": 417,
"sessions": [
{
"id": 12375,
"student_count": 11,
"course_name": "HAM Radio Introduction",
"instructor_name": "Pat S",
"datetime": "2019-01-24T02:00:00Z",
"course": 417,
"is_cancelled": false,
"old_instructor": "Pat S",
"cost": "0.00",
"max_students": null,
"instructor": null
}
],
"name": "HAM Radio Introduction",
"description": "text",
"is_old": true
}
:json boolean is_old: True if imported from old portal.
:json description: Text separated by \\n if is_old, otherwise HTML.
.. http:post:: /courses/
.. http:put:: /courses/(id)/
.. http:patch:: /courses/(id)/
Instructors and admins only.
:param id: The course's ID.
:json name:
:json boolean is_old:
:json description:
:requestheader Authorization: ``Token <token>``
Sessions
--------
Classes are called sessions in the API because of old portal models
and "class" keyword conflict.
A session (class) belongs to a course and has a specific date, time,
instructor, and cost.
.. http:get:: /sessions/
List of the 20 next sessions.
Truncated.
.. sourcecode:: json
{
"count": 20,
"next": null,
"previous": null,
"results": [
{
"id": 13476,
"student_count": 0,
"course_name": "CAD: Introduction to 3D CAD (Fusion)",
"instructor_name": "Mike M",
"datetime": "2020-01-18T16:30:00Z",
"course": 253,
"is_cancelled": false,
"old_instructor": "Mike M",
"cost": "0.00",
"max_students": null,
"instructor": null
}
]
}
:json student_count: Number of students registered, excluding withdrawn.
.. http:get:: /sessions/(id)/
:param id: The course's ID.
.. sourcecode:: json
{
"id": 13476,
"student_count": 0,
"course_name": "CAD: Introduction to 3D CAD (Fusion)",
"instructor_name": "Mike M",
"datetime": "2020-01-18T16:30:00Z",
"course": 253,
"students": [],
"is_cancelled": false,
"old_instructor": "Mike M",
"cost": "0.00",
"max_students": null,
"instructor": null
}
.. http:post:: /sessions/
.. http:put:: /sessions/(id)/
.. http:patch:: /sessions/(id)/
Instructors and admins only.
:param id: The session's ID.
:json datetime: UTC ISO 8601, YYYY-MM-DDTHH:MM:SSZ
:json int course: ID of the course it belongs to.
:json boolean is_cancelled: Only for display.
:json decimal cost: 0 if free.
:json int max_students: optional
:requestheader Authorization: ``Token <token>``
Training
--------
A training object is created when a member registers for a session (class).
.. http:get:: /training/(id)/
Retrieve a training object. Users can only view their own. Instructors can
view their students'. Admins can view anyone's.
:param id: The training object's ID.
:requestheader Authorization: ``Token <token>``
.. sourcecode:: json
{
"id": 971,
"attendance_status": "Confirmed",
"session": 11073,
"student_name": "Tanner Collin",
"member_id": 1685,
"sign_up_date": null,
"paid_date": null,
"user": 113
}
.. http:post:: /training/
Register for a session (class).
**Users**
:json attendance_status: One of: ``Waiting for payment``, ``Withdrawn``
:json int session: The session (class) to register for.
**Instructors and Admins**
:json attendance_status: One of: ``Waiting for payment``, ``Withdrawn``,
``Rescheduled``, ``No-show``, ``Attended``, ``Confirmed``
:json int session: The session (class) to register for.
:requestheader Authorization: ``Token <token>``
.. http:put:: /training/(id)/
.. http:patch:: /training/(id)/
Edit attendance status.
Same params as POST.
:requestheader Authorization: ``Token <token>``
Cards
-----
Cards are sent to Protospace's door controllers to grant access to the
building. Only active cards of unpaused members are sent.
.. http:get:: /cards/(id)/
Retrieve a card. Users can only view their own, admins can view anyone's.
:param id: The card object's ID.
:requestheader Authorization: ``Token <token>``
.. sourcecode:: json
{
"id": 392,
"card_number": "text",
"member_id": 1685,
"active_status": "card_active",
"notes": "Tanner Collin",
"last_seen_at": "2020-01-20",
"user": 113
}
.. http:post:: /cards/
.. http:put:: /cards/(id)/
.. http:patch:: /cards/(id)/
.. http:delete:: /cards/(id)/
Admins only. Don't change the status when pausing a member, paused member's
cards are filtered out automatically.
:param id: The card object's ID.
:json card_number: Usually a 10 character hex string.
:json int member_id: Which member the card belongs to.
:json active_status: One of: ``card_blocked``, ``card_inactive``,
``card_member_blocked``, ``card_active``
:json notes: optional
:requestheader Authorization: ``Token <token>``
Door
----
Private route that the door controllers should poll for a list of cards
allowed to scan into the building.
.. http:get:: /door/
List all active cards of unpaused members.
Authorization with the door API token set in secrets.py is required.
Use "Bearer" instead of "Token" like in the other routes.
:requestheader Authorization: ``Bearer <door API token>``
**Example response**
Truncated.
.. sourcecode:: json
{
"0000001234": "Tanner C (1685)",
"000000ABCD": "Tanner C (1685)",
}
:json key: The dict keys are the card numbers.
:json value: Member's name and ID.
.. http:post:: /door/(card_number)/seen/
Update card's last_seen_at to today.
This doesn't do any fancy logging yet.
:param card_number: Usually a 10 character hex string.
No authentication required.
Ping
----
.. http:post:: /ping/
Does nothing except check if a user's auth token is still valid.
:requestheader Authorization: ``Token <token>``
**Response**
:status 200:
Stats
-----
Public route that returns stats about Spaceport and Protospace.
.. http:get:: /stats/
Retrieve the stats object. This is very inexpensive, so feel free to call frequently.
**Example response**
.. sourcecode:: json
{
"bay_108_temp": 22.1,
"bay_110_temp": 22.5,
"card_scans": 7,
"last_card_change": 1595844608.7921524,
"green_count": 153,
"member_count": 191,
"paused_count": 1071,
"minecraft_players": ["tanner6"],
"next_clean": "2020-08-08T16:00:30Z",
"next_meeting": "2020-08-20T01:00:20Z",
"track": {
"FRICKIN-LASER": 1595882018.228888,
"TROTECS300": 1595797812.8726459
}
}
:json bay_108_temp: Celsius temperature of bay 108.
:json bay_110_temp: Celsius temperature of bay 110.
:json card_scans: Number of unique card scans that day.
:json last_card_change: Time of last update to member cards.
:json green_count: Number of current and prepaid members.
:json member_count: Total number of Protospace members.
:json paused_count: Number of expired (old) members.
:json minecraft_players: A list of players currently on the Minecraft server.
:json next_clean: UTC datetime of next monthly clean.
:json next_meeting: UTC datetime of next member's meeting.
:json track: A dictionary of computer names and their last ping's epoch time.
.. http:post:: /stats/track/
Update the time at which a computer was last seen.
Used to track when the lasers are in use.
:param name: The computer's hostname.
No authentication required.

View File

@ -1,82 +0,0 @@
API Overview
============
The current API URL is: https://api.spaceport.dns.t0.vc/
The Spaceport API uses REST. JSON is returned by all API responses including
errors and HTTP response status codes are to designate success and failure.
Request bodies can be JSON or form data.
All API routes require a trailing slash. This is a Django default and you'll get
a 301 redirect if you forget it.
Authentication
--------------
All API routes require authentication with a token. The
token is returned on registration and login. The token needs to be placed in the
``Authorization`` request header like this: ``Token <token>``.
**Example**
Login response:
.. sourcecode:: json
{"key":"1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444"}
Add the following header to requests:
.. sourcecode:: text
Authorization: Token 1fb8ef73f118c5de1f9ba4939a76b3f3b0bc7444
Quick Reference
---------------
.. http:post:: /registration/
.. http:post:: /rest-auth/login/
.. http:get:: /user/
.. http:post:: /password/change/
.. http:post:: /password/reset/
.. http:post:: /password/reset/confirm/
.. http:get:: /members/(id)/
.. http:post:: /members/
.. http:patch:: /members/(id)/
.. http:put:: /members/(id)/
.. http:post:: /members/(id)/pause/
.. http:post:: /members/(id)/unpause/
.. http:post:: /search/
.. http:get:: /search/(id)/
.. http:get:: /transactions/(id)/
.. http:get:: /transactions/
.. http:post:: /transactions/
.. http:patch:: /transactions/(id)
.. http:put:: /transactions/(id)/
.. http:post:: /transactions/(id)/report/
.. http:get:: /courses/
.. http:get:: /courses/(id)/
.. http:post:: /courses/
.. http:put:: /courses/(id)/
.. http:patch:: /courses/(id)/
.. http:get:: /sessions/
.. http:get:: /sessions/(id)/
.. http:post:: /sessions/
.. http:put:: /sessions/(id)/
.. http:patch:: /sessions/(id)/
.. http:get:: /training/(id)/
.. http:post:: /training/
.. http:put:: /training/(id)/
.. http:patch:: /training/(id)/
.. http:get:: /cards/(id)/
.. http:post:: /cards/
.. http:put:: /cards/(id)/
.. http:patch:: /cards/(id)/
.. http:delete:: /cards/(id)/
.. http:get:: /door/
.. http:post:: /door/(card_number)/seen/
.. http:post:: /ping/
.. http:get:: /stats/
.. http:post:: /stats/track/

View File

@ -14,6 +14,7 @@
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from recommonmark.parser import CommonMarkParser
# -- Project information -----------------------------------------------------
@ -28,10 +29,17 @@ author = 'Tanner Collin'
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx_rtd_theme',
'sphinxcontrib.httpdomain',
'recommonmark',
]
source_suffix = ['.rst', '.md']
source_parsers = {
'.md': 'CommonMarkParser',
}
known_url_schemes = ['http', 'https']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View File

@ -0,0 +1,60 @@
# API Server Development Setup
This guide assumes you are using Debian GNU/Linux 10 or Ubuntu 20.04 LTS. If you
aren't, just spin up a VPN with the correct version. Things break if you don't.
## Install Dependencies
```
$ sudo apt update
$ sudo apt install build-essential python3 python3-dev libffi-dev python3-pip python3-virtualenv memcached git
```
Clone the repo. Skip this step if you already have it:
```
$ git clone https://github.com/Protospace/spaceport.git
```
Set up Python:
```
$ cd spaceport/apiserver/
$ python3 -m virtualenv -p python3 env
$ source env/bin/activate
(env) $ pip install -r requirements.txt
```
Copy the secrets file and optionally fill out values depending on which
[[integrations]] you wish to enable.
```
(env) $ cp apiserver/secrets.py.example apiserver/secrets.py
(env) $ sensible-editor apiserver/secrets.py # optional
```
## Initialize Database
Set up the database:
```
(env) $ python manage.py makemigrations
(env) $ python manage.py makemigrations api
(env) $ python manage.py migrate
```
Create a super user so you can manage who's director or staff:
```
(env) $ python manage.py createsuperuser --email admin@example.com --username admin
```
## Running
Run the development server:
```
$ source env/bin/activate
(env) $ DEBUG=true python manage.py runserver
```

View File

@ -15,3 +15,4 @@ Spaceport Documentation
apioverview
api
ldap
dev_apiserver

View File

@ -1,120 +0,0 @@
Feature Specs
=============
This is an outline of current and future features of Spaceport.
Plain
Implemented
Bold
Not yet implemented
Web Client
----------
- Home
- Login
- Sign up
- Register a new account
- Claim an old account on the portal
- Profile
- Photo
- Status
- Details
- Application forms
- Latest transactions
- Public bio
- Private notes
- Quick links
- Stats
- Next meetings
- Member counts
- Graphs of member counts
- Bay temperatures
- Minecraft server players
- Account settings
- Edit member details
- Change password
- Log out from everywhere
- **Add custom CSS**
- Transactions
- View list of transactions
- View transaction details
- Report an error in transaction
- Admins can edit transactions
- Paymaster
- Buy snacks, pop, coffee
- Pay member dues
- Pay for locker storage
- Donate
- Training
- View list of training
- Cards
- View list of access cards
- View door alarm code + wifi pass
- View API key
- Member list
- Search for members by name, email, or ID
- View member photo, status, and joined date
- Admin member details
- View all of a member's details
- Edit member details
- Make member an instructor
- Pause / unpause member
- View member's application forms
- View member cards
- Edit member cards
- View member transactions
- Edit member transactions
- Course list
- View list of courses
- View course details
- View list of classes for a course
- Instructor course list
- Add a new course
- Edit course details
- Create a class for a course
- Class list
- View upcoming classes
- View recent classes
- View class details
- Sign up for a course
- Pay for course with paypal
- Withdraw from a course
- Instructor class list
- Edit class details
- **Add a custom note for a class**
- Mark off students' attendance
- View students' emails
- Print attendance sheet
- Transporter
- Public paste bin to share text
- Admin Page
- View recent backup times
- View all database changes
- Admin Transaction list
- View reported transactions
- Correct reported transactions
- View all transactions by month