settings.py 8.37 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

50
51
# Email Format
EMAIL_REGEX = '^.+@.+$'
adietmue's avatar
adietmue committed
52

53
54
55
56
# More Feedback when creating something: Return all fields
BANDWIDTH_SAVER = False


57
58
59
60
61
62
63
# Disable bulk insert
# They are not compatible with uniqueness constraints
# (see more here: https://github.com/pyeve/eve/issues/691)
# In our case, we need time and room uniqueness nearly everywhere => disabled
BULK_ENABLED = False


64
# A schema for required start/end time tuple
65
TIMESPAN_SCHEMA = {
66
67
68
69
70
71
72
73
74
75
76
77
78
    'type': 'dict',
    'schema': {
        'start': {
            'type': 'datetime',
            'nullable': False,
            'required': True,
        },
        'end': {
            'type': 'datetime',
            'nullable': False,
            'required': True,
        },
    },
79
    'start_before_end': True,
80
81
82
}


83
84
85
86
# Same as Eve, but include 403
STANDARD_ERRORS = [400, 401, 403, 404, 405, 406, 409, 410, 412, 422, 428]


87
88
# Resources
DOMAIN = {
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
    'assistants': {
        'user_methods': ['GET'],

        'schema': {
            'name': {
                'type': 'string',
                'maxlength': 100,
                'required': True,
                'nullable': False,
                'empty': False,
            },
            'email': {
                'type': 'string',
                'maxlength': 100,
                'regex': EMAIL_REGEX,
                'required': True,
                'unique': True,
                'nullable': True,
            }
        }
    },

111
    'lectures': {
112
113
114

        'user_methods': ['GET'],

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
        '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
            },
        },
    },

    'courses': {
140
141
142

        'user_methods': ['GET'],

143
144
145
146
147
148
149
150
        'schema': {
            'lecture': {
                'type': 'objectid',
                'data_relation': {
                    'resource': 'lectures',
                    'field': '_id',
                    'embeddable': True
                },
151
                'not_patchable': True,  # Course is tied to lecture
152
                'required': True,
153
154
            },
            'assistant': {
155
156
157
158
159
160
161
                'type': 'objectid',
                'data_relation': {
                    'resource': 'assistants',
                    'field': '_id',
                    'embeddable': True,
                    'unique_assistant_booking': True,
                },
162
163
            },

164
            'signup': TIMESPAN_SCHEMA,
165
166
167

            'datetimes': {
                'type': 'list',
168
                'schema': TIMESPAN_SCHEMA,
169
170
                'no_time_overlap': True,
                'unique_room_booking': True,
171
                'unique_assistant_booking': True,
172
173
174
175
176
177
            },
            'room': {
                'type': 'string',
                'maxlength': 100,
                'nullable': False,
                'empty': False,
178
                'unique_room_booking': True,
179
180
181
182
183
            },
            'spots': {
                'type': 'integer',
                'min': 1,
                'required': True,
184
                'nullable': False,
185
186
187
188
189
            }
        },
    },

    'signups': {
190
191
        # Signup for a user to a course

192
193
        'user_methods': ['GET', 'POST', 'PATCH', 'DELETE'],

194
195
196
197
198
199
200
        'schema': {
            'nethz': {
                'type': 'string',
                'maxlength': 10,
                'empty': False,
                'nullable': False,
                'required': True,
adietmue's avatar
adietmue committed
201
                'only_own_nethz': True,
202
                'not_patchable': True,  # Signup is tied to user
203
204
205
206
207
208
209
210
            },
            'course': {
                'type': 'objectid',
                'data_relation': {
                    'resource': 'courses',
                    'field': '_id',
                    'embeddable': True
                },
adietmue's avatar
adietmue committed
211
                'unique_combination': ['nethz'],
212
                'required': True,
213
                'no_course_overlap': 'signups',
214
215
216
            },
            'status': {
                'type': 'string',
217
                'allowed': ['waiting', 'reserved', 'accepted'],
218
                'readonly': True,
219
                'default': 'waiting',
220
221
            },
        },
222
223
224
225
    },

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

228
229
        'user_methods': ['GET', 'POST', 'PATCH', 'DELETE'],

230
231
232
233
234
235
236
237
        'schema': {
            'nethz': {
                'type': 'string',
                'maxlength': 10,
                'empty': False,
                'nullable': False,
                'required': True,
                'only_own_nethz': True,
238
                'not_patchable': True,  # Signup is tied to user
239
            },
240
241
242
243
244
245
            'course': {
                'type': 'objectid',
                'data_relation': {
                    'resource': 'courses',
                    'field': '_id',
                    'embeddable': True
246
                },
247
248
                'unique_combination': ['nethz'],
                'required': True,
249
                'no_course_overlap': 'selections',
250
251
252
253
254
            },
        },
    },

    'payments': {
255
256
257
258
        # 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
259

260
        # Only admins can delete payments
261
262
263
        # Also, there is no reason to ever change a payment.
        'user_methods': ['GET', 'POST'],

264
265
266
267
268
269
270
271
272
273
        'schema': {
            'signups': {
                'type': 'list',
                'schema': {
                    'type': 'objectid',
                    'data_relation': {
                        'resource': 'signups',
                        'field': '_id',
                        'embeddable': True
                    },
274
275
276
277
                    # No signups on waiting list
                    'no_waiting': True,
                    # No signups which have already been paid
                    'no_accepted': True,
278
                },
279
                'no_copies': True,
280
281
                'required': True,
                'nullable': False,
282
283
            },
            # Admins may leave this field empty
284
            # However, it still has to be sent, even if  empty or None
285
286
287
288
289
290
291
            'token': {
                'type': 'string',
                'unique': True,
                'required': True,
                'nullable': True,
                'only_admin_empty': True,
            },
292
            'charge_id': {  # Set by payment backend
293
294
295
296
297
                'type': 'string',
                'unique': True,
                'required': False,
                'nullable': True,
            },
298
            'amount': {  # Set by payment backend
299
300
301
                'type': 'integer',
                'required': False,
                'nullable': True,
302
303
            }
        }
304
305
    }
}