settings.py 7.79 KB
Newer Older
1
2
3
4
"""Data Model and General Configuration of Eve.

Check out [the Eve docs for configuration](http://python-eve.org/config.html)
if you are unsure about some of the settings.
5

6
7
8
Our schema requires customized data validation. These validation rules are
implemented in `validation.py`.
Some validation rules are still missing, they are marked with TODO in the
9
schema directly.
10
"""
adietmue's avatar
adietmue committed
11

12
13
from os import environ

14
15
16
# CORS
X_DOMAINS = '*'
X_HEADERS = ['Authorization', 'If-Match', 'If-Modified-Since', 'Content-Type']
17

adietmue's avatar
adietmue committed
18
# AMIVAPI URL and Admin Group
19
20
AMIVAPI_URL = 'https://amiv-api.ethz.ch'
ADMIN_GROUP_NAME = 'PVK Admins'
21

22
# DB (can be set by env for easier CI tests)
23
MONGO_HOST = environ.get('MONGO_HOST', 'localhost')
24
25
26
27
MONGO_PORT = environ.get('MONGO_PORT', 27017)
MONGO_DBNAME = environ.get('MONGO_DBNAME', 'pvk')
MONGO_USERNAME = environ.get('MONGO_USERNAME', 'pvkuser')
MONGO_PASSWORD = environ.get('MONGO_PASSWORD', 'pvkpass')
28

29

30
31
32
# Only JSON, simplifies hooks
XML = False

adietmue's avatar
adietmue committed
33

34
RESOURCE_METHODS = ['GET', 'POST']
adietmue's avatar
adietmue committed
35
36
ITEM_METHODS = ['GET', 'PATCH', 'DELETE']

37

38
39
40
41
42
43
44
45
46
# Stripe API Key
# TODO: Not a good idea to keep this in the repo
STRIPE_API_KEY = 'sk_test_KUiZO8E2VKGMmm94u4t5YPnL'


# Price per course in "rappen"
COURSE_PRICE = 1000


adietmue's avatar
adietmue committed
47
48
# ISO 8601 time format instead of rfc1123
DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
49

adietmue's avatar
adietmue committed
50

51
52
53
54
# More Feedback when creating something: Return all fields
BANDWIDTH_SAVER = False


55
# A schema for required start/end time tuple
56
TIMESPAN_SCHEMA = {
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    'type': 'dict',
    'schema': {
        'start': {
            'type': 'datetime',
            'nullable': False,
            'required': True,
        },
        'end': {
            'type': 'datetime',
            'nullable': False,
            'required': True,
        },
    },
}


73
74
75
76
# Same as Eve, but include 403
STANDARD_ERRORS = [400, 401, 403, 404, 405, 406, 409, 410, 412, 422, 428]


77
78
79
# Resources
DOMAIN = {
    'lectures': {
80
81
82

        'user_methods': ['GET'],

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
        'schema': {
            'title': {
                'type': 'string',
                'maxlength': 100,
                'unique': True,
                'required': True,
                'nullable': False,
                'empty': False,
            },
            'department': {
                'type': 'string',
                'allowed': ['itet', 'mavt'],
                'required': True,
                'nullable': False,
            },
            'year': {
                'type': 'integer',
                'min': 1,
                'max': 3,
                'required': True
            },
104
105
106
107
108
109
110
111
            'assistants': {
                # List of nethz of assistants
                'type': 'list',
                'schema': {
                    'type': 'string',
                    'maxlength': 10,
                    'empty': False,
                    'nullable': False,
adietmue's avatar
adietmue committed
112
                },
113
                # TODO: Not the same nethz twice
114
                # TODO: Is nethz enough here?
115
            }
116
117
118
119
        },
    },

    'courses': {
120
121
122

        'user_methods': ['GET'],

123
124
125
126
127
128
129
130
        'schema': {
            'lecture': {
                'type': 'objectid',
                'data_relation': {
                    'resource': 'lectures',
                    'field': '_id',
                    'embeddable': True
                },
131
                'not_patchable': True,  # Course is tied to lecture
132
133
            },
            'assistant': {
adietmue's avatar
adietmue committed
134
                'type': 'string',
135
                # TODO: Assistant needs to exist for lecture
136
137
            },

138
            'signup': TIMESPAN_SCHEMA,
139
140
141

            'datetimes': {
                'type': 'list',
142
143
                'schema': TIMESPAN_SCHEMA,
                # TODO: Timeslots must not overlap
144
145
146
147
148
149
150
151
            },
            'room': {
                'type': 'string',
                'maxlength': 100,
                'unique': True,
                'required': True,
                'nullable': False,
                'empty': False,
152
                # TODO: Room must be empty for time slot
153
154
155
156
157
158
159
160
161
162
163
            },
            'spots': {
                'type': 'integer',
                'min': 1,
                'required': True,
                'nullable': False
            }
        },
    },

    'signups': {
164
165
        # Signup for a user to a course

166
167
        'user_methods': ['GET', 'POST', 'PATCH', 'DELETE'],

168
169
170
171
172
173
174
        'schema': {
            'nethz': {
                'type': 'string',
                'maxlength': 10,
                'empty': False,
                'nullable': False,
                'required': True,
adietmue's avatar
adietmue committed
175
                'only_own_nethz': True,
176
                'not_patchable': True,  # Signup is tied to user
177
178
179
180
181
182
183
184
            },
            'course': {
                'type': 'objectid',
                'data_relation': {
                    'resource': 'courses',
                    'field': '_id',
                    'embeddable': True
                },
adietmue's avatar
adietmue committed
185
                'unique_combination': ['nethz'],
186
                'required': True,
187
                # TODO: No overlapping courses
188
189
190
            },
            'status': {
                'type': 'string',
191
                'allowed': ['waiting', 'reserved', 'accepted'],
192
                'readonly': True,
193
                'default': 'waiting',
194
195
            },
        },
196
197
198
199
    },

    'selections': {
        # Easy way for users to safe their selections before signup is open
200
        # exactly like singups, but without status
201

202
203
        'user_methods': ['GET', 'POST', 'PATCH', 'DELETE'],

204
205
206
207
208
209
210
211
        'schema': {
            'nethz': {
                'type': 'string',
                'maxlength': 10,
                'empty': False,
                'nullable': False,
                'required': True,
                'only_own_nethz': True,
212
                'not_patchable': True,  # Signup is tied to user
213
            },
214
215
216
217
218
219
            'course': {
                'type': 'objectid',
                'data_relation': {
                    'resource': 'courses',
                    'field': '_id',
                    'embeddable': True
220
                },
221
222
223
                'unique_combination': ['nethz'],
                'required': True,
                # TODO: No overlapping courses
224
225
226
227
228
            },
        },
    },

    'payments': {
229
230
231
232
        # Endpoint for payments via Stripe.

        # charge_id is a unique identifier which allows us to track the payment with Stripe
        # Admins can however create payments without a charge_id
233

234
        # Only admins can delete payments
235
236
237
238
239
        # Also, there is no reason to ever change a payment.
        'user_methods': ['GET', 'POST'],

        # Bulk inserts don't make sense here, so we disallow them
        'bulk_enabled': False,
240

241
242
243
244
245
246
247
248
249
250
        'schema': {
            'signups': {
                'type': 'list',
                'schema': {
                    'type': 'objectid',
                    'data_relation': {
                        'resource': 'signups',
                        'field': '_id',
                        'embeddable': True
                    },
251
252
                    'no_waiting': True, # No signups on waiting list
                    'no_accepted': True, # No signups which have already been paid
253
                },
254
                'no_copies': True,
255
256
                'required': True,
                'nullable': False,
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
            },
            # Admins may leave this field empty
            # However, it still has to be sent, even if it contains an empty string / None
            'token': {
                'type': 'string',
                'unique': True,
                'required': True,
                'nullable': True,
                'only_admin_empty': True,
            },
            'charge_id': { # Set by backend
                'type': 'string',
                'unique': True,
                'required': False,
                'nullable': True,
            },
            'amount': { # Set by backend
                'type': 'integer',
                'required': False,
                'nullable': True,
277
278
            }
        }
279
280
    }
}