Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3318551
Add /api/signup-post endpoint
krestenlaust Dec 26, 2024
14ab546
Make schemes more generic
krestenlaust Dec 26, 2024
b7df05b
Add /api/signup-post output
krestenlaust Dec 26, 2024
4112320
fixup! Add /api/signup-post output
krestenlaust Dec 28, 2024
36f7127
Simplify /api/signup-post endpoint
krestenlaust Dec 28, 2024
f807d90
Add implementation for /api/signup-post endpoint
krestenlaust Dec 28, 2024
bdb0592
Return only signup ID and due
krestenlaust Dec 28, 2024
649cb36
Rename local variable
krestenlaust Jan 11, 2025
44ed033
Move post_signup
krestenlaust Jan 11, 2025
6ceacf8
Add api/signup/status endpoint to spec
krestenlaust Jan 11, 2025
bbbb15a
Update /api/signup/status to take in username
krestenlaust Jan 13, 2025
bdc077f
Merge branch 'next' into feat/api-signup
krestenlaust Jan 13, 2025
da96b25
fixup! Merge branch 'next' into feat/api-signup
krestenlaust Jan 13, 2025
8d34ee7
Implement /api/signup/status
krestenlaust Jan 13, 2025
ff3905c
fixup! Update /api/signup/status to take in username
krestenlaust Jan 13, 2025
202fc8c
Increment API version to 1.1.1
krestenlaust Jan 13, 2025
bd0fc87
Merge branch 'next' into feat/api-signup
krestenlaust Jan 15, 2025
36a9a9a
Add CSRF exemption
krestenlaust Jan 15, 2025
5fc7abd
Update response to fit spec
krestenlaust Jan 15, 2025
cd9c700
Add tests to validate form on API call
krestenlaust Jan 15, 2025
1168655
fixup! Add tests to validate form on API call
krestenlaust Jan 15, 2025
67f204c
Handle duplicate username in perform_signup
krestenlaust Jan 15, 2025
7be4a15
Internally map 'education' parameter
krestenlaust Feb 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 155 additions & 1 deletion openapi/stregsystem.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ info:
Existing client software utilizing the API include Stregsystem-CLI (STS) and Fappen (F-Club Web App).

Disclaimer - The implementation is not generated using this specification, therefore they can get out of sync if changes are made directly to the codebase without updating the OpenAPI specification file accordingly.
version: "1.1"
version: "1.1.1"
externalDocs:
description: Find out more about Stregsystemet at GitHub.
url: https://github.com/f-klubben/stregsystemet/
Expand All @@ -21,6 +21,8 @@ tags:
description: Related to the products.
- name: Sale
description: Related to performing a sale.
- name: Signup
description: Related to registration of new members.
paths:
/api/member:
get:
Expand Down Expand Up @@ -159,6 +161,38 @@ paths:
$ref: '#/components/responses/SaleSuccess'
'400':
$ref: '#/components/responses/Member_RoomIdParameter_BadResponse'
/api/signup:
post:
tags:
- Signup
summary: Posts a signup
description: Performs a signup using member info.
operationId: api_signup
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/signup_input'
responses:
'200':
$ref: '#/components/responses/SignupSuccess'
'400':
$ref: '#/components/responses/Signup_BadResponse'
/api/signup/status:
get:
tags:
- Signup
summary: Gets status regarding a signup
description: Retrieves the signup status for a specific member by username.
operationId: api_signup_status
parameters:
- $ref: '#/components/parameters/username_param'
responses:
'200':
$ref: '#/components/responses/SignupStatus'
'400':
$ref: '#/components/responses/MemberUsernameParameter_BadResponse'
components:
examples:
MemberNotFoundExample:
Expand All @@ -182,7 +216,20 @@ components:
MissingMemberUsernameExample:
summary: No username given
value: "Parameter missing: username"
UsernameTakenExample:
summary: Member with that username already exist
value: "Username taken"
MissingOrInvalidParameterExample:
summary: A parameter is invalid or missing
value: "Parameter invalid: <parameter>"
parameters:
signup_id_param:
name: signup_id
in: query
description: Signup ID of the signup to retrieve.
required: true
schema:
$ref: '#/components/schemas/signup_id'
member_id_param:
name: member_id
in: query
Expand Down Expand Up @@ -239,6 +286,12 @@ components:
missingMemberUsernameMessage:
type: string
example: "Parameter missing: username"
usernameTakenMessage:
type: string
example: "Username taken"
invalidParameterMessage:
type: string
example: "Parameter invalid: <parameter>"
balance:
type: integer
example: 20000
Expand All @@ -257,6 +310,35 @@ components:
room_id:
type: integer
example: 10
email:
type: string
format: email
example: [email protected]
firstname:
type: string
example: Kresten
lastname:
type: string
example: Laust
education:
type: string
description: Acknowledged shortening, e.g. sw/ixd/dad/dat
example: sw
gender:
type: string
enum:
- U
- M
- F
example: M
approval_status:
type: string
description: U = Unreviewed, A = Approved, I = Ignored, R = Rejected.
enum:
- U
- A
- I
- R
timestamp:
type: string
format: date-time
Expand All @@ -274,13 +356,24 @@ components:
type: integer
example: 1800
stregoere_balance:
type: integer
example: 15000
stregoere_due:
type: integer
example: 20000
stregkroner_balance:
description: Stregbalance in kroner, only used in API-Sale
type: number
format: float
example: 182.00
signup_id:
type: integer
example: 5
named_products_example:
type: object
properties:
beer:
$ref: '#/components/schemas/product_id'
sale_input:
type: object
properties:
Expand All @@ -290,6 +383,21 @@ components:
$ref: '#/components/schemas/buystring'
room:
$ref: '#/components/schemas/room_id'
signup_input:
type: object
properties:
education:
$ref: '#/components/schemas/education'
username:
$ref: '#/components/schemas/username'
email:
$ref: '#/components/schemas/email'
firstname:
$ref: '#/components/schemas/firstname'
lastname:
$ref: '#/components/schemas/lastname'
gender:
$ref: '#/components/schemas/gender'
active_product:
type: object
properties:
Expand Down Expand Up @@ -359,6 +467,13 @@ components:
member_has_low_balance:
type: boolean
example: false
signup_values_result_example:
type: object
properties:
due:
$ref: '#/components/schemas/stregoere_due'
username:
$ref: '#/components/schemas/username'
sale_values_result_example:
type: object
properties:
Expand Down Expand Up @@ -472,6 +587,17 @@ components:
properties:
sales:
$ref: '#/components/schemas/sales'
SignupStatus:
description: Signup information found.
content:
application/json:
schema:
type: object
properties:
due:
$ref: '#/components/schemas/stregoere_due'
status:
$ref: '#/components/schemas/approval_status'
NamedProducts:
description: Dictionary of all named_product names.
content:
Expand Down Expand Up @@ -511,6 +637,21 @@ components:
example: "OK"
values:
$ref: '#/components/schemas/sale_values_result_example'
SignupSuccess:
description: An object containing info regarding the signup.
content:
application/json:
schema:
type: object
properties:
status:
type: integer
example: 200
msg:
type: string
example: "OK"
values:
$ref: '#/components/schemas/signup_values_result_example'
QRCodeGenerated:
description: QR code with link to open MobilePay with the provided information.
content:
Expand Down Expand Up @@ -594,3 +735,16 @@ components:
$ref: '#/components/examples/InvalidRoomIdExample'
missingRoomId:
$ref: '#/components/examples/MissingRoomIdExample'
Signup_BadResponse:
description: Username is taken, missing parameter, or invalid parameter.
content:
text/html:
schema:
oneOf:
- $ref: '#/components/schemas/usernameTakenMessage'
- $ref: '#/components/schemas/invalidParameterMessage'
examples:
usernameTaken:
$ref: '#/components/examples/UsernameTakenExample'
invalidParameter:
$ref: '#/components/examples/MissingOrInvalidParameterExample'
73 changes: 73 additions & 0 deletions stregsystem/tests.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import datetime
import json
from collections import Counter
from copy import deepcopy
from unittest import mock
Expand Down Expand Up @@ -2272,3 +2273,75 @@ def test_welcome_mail_paid_approved(self, mock_mail_method: MagicMock):

signup_request.approve()
mock_mail_method.assert_called_once()


class ApiTests(TestCase):
"""
A lot of the API testing is done separately using Dredd and OpenAPI.
These are edge-cases which can't be expressed in OpenAPI.
"""

def setUp(self):
member = Member.objects.create(username="martin_p", email="[email protected]", signup_due_paid=False)
member.save()

def test_signup_duplicate_username(self):
response = self.client.post(
reverse('api_signup'),
json.dumps(
{
'education': "sw",
'username': "martin_p", # Note: Duplicate username
'firstname': "Martin",
'lastname': "P.",
'email': "[email protected]",
'gender': "M",
}
),
content_type="application/json",
)

self.assertNotEquals(response.status_code, 200)

def test_signup_partial_form_no_name(self):
response = self.client.post(
reverse('api_signup'),
json.dumps({'education': "sw", 'username': "martin_p2", 'email': "[email protected]", 'gender': "M"}),
content_type="application/json",
)

self.assertNotEquals(response.status_code, 200)

def test_signup_partial_form_no_username(self):
response = self.client.post(
reverse('api_signup'),
json.dumps(
{
'education': "sw",
'firstname': "Martin",
'lastname': "P.",
'email': "[email protected]",
'gender': "M",
}
),
content_type="application/json",
)

self.assertNotEquals(response.status_code, 200)

def test_signup_partial_form_no_education(self):
response = self.client.post(
reverse('api_signup'),
json.dumps(
{
'username': "martin_p2",
'firstname': "Martin",
'lastname': "P.",
'email': "[email protected]",
'gender': "M",
}
),
content_type="application/json",
)

self.assertNotEquals(response.status_code, 200)
2 changes: 2 additions & 0 deletions stregsystem/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@
re_path(r'^api/products/active_products$', views.get_active_items, name="api_active_products"),
re_path(r'^api/products/category_mappings$', views.get_product_category_mappings, name="api_product_mappings"),
re_path(r'^api/sale$', views.api_sale, name="api_sale"),
re_path(r'^api/signup$', views.post_signup, name="api_signup"),
re_path(r'^api/signup/status', views.get_signup_status, name="api_signup_status"),
]
Loading
Loading