├── .gitignore ├── requirements.txt ├── CHANGELOG.md ├── gevent_web.py ├── README.md ├── server.py └── settings.sample.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | settings.py 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Eve==0.6.1 2 | gevent==1.0.2 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.1.0 2 | - [Update] Remove topics field as default embedded field on meta_scheam 3 | -------------------------------------------------------------------------------- /gevent_web.py: -------------------------------------------------------------------------------- 1 | # ref: http://flask.pocoo.org/docs/0.10/deploying/wsgi-standalone/ 2 | from gevent.wsgi import WSGIServer 3 | from server import app 4 | 5 | http_server = WSGIServer(('', 80), app) 6 | http_server.serve_forever() 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## tr-projects-rest 2 | 3 | twreporter middle-ware rest-api server 4 | 5 | ## Requirements 6 | ``` shell 7 | # linux 8 | apt-get install libevent-dev 9 | apt-get install python-all-dev 10 | apt-get install python-pip 11 | pip install -r requirements.txt 12 | 13 | # mac 14 | # install homebrew first 15 | brew install python 16 | /usr/local/bin/pip install -r requirements.txt 17 | ``` 18 | 19 | ## Development 20 | ``` shell 21 | # set mongo database in settings.py 22 | python server.py 23 | 24 | # mac 25 | /usr/local/bin/python server.py 26 | ``` 27 | 28 | ## Deploy 29 | 30 | ``` shell 31 | sudo python gevent_web.py & 32 | ``` 33 | 34 | ## Script 35 | 36 | - scripts have been moved to https://github.com/twreporter/tr-projects-crontab 37 | 38 | ## Examples 39 | 40 | - http://localhost:8080/posts 41 | - http://localhost:8080/posts/the-post-slug 42 | - http://localhost:8080/posts?embedded={"authors":1,"tags":1,"categories":1} 43 | - http://localhost:8080/posts?content_type=html 44 | - http://localhost:8080/contacts?where={"_id":{"$in":["56cec38678c3ee45f715b077","56cec37a78c3ee45f715afd6"]}} 45 | - http://localhost:8080/contacts?where={"_id":{"$in":["56cec38678c3ee45f715b077","56cec37a78c3ee45f715afd6"]}, "email":"feugiat.nec.diam@idante.org"} 46 | - http://localhost:8080/posts?where={"tags":{"$in":["56d01094b4710c3602715ad2"]}} 47 | - http://localhost:8080/users/ 48 | - http://localhost:8080/contacts 49 | 50 | ### Show nested entities in response. 51 | - http://localhost:8080/posts?embedded={"authors":1,"tags":1,"categories":1} 52 | - http://localhost:8080/posts/the-post-slug?embedded={"authors":1,"tags":1,"categories":1} 53 | 54 | 55 | ### Conditional selection 56 | - http://localhost:8080/contacts?where={"_id":{"$in":["56cec38678c3ee45f715b077","56cec37a78c3ee45f715afd6"]}} 57 | - http://localhost:8080/contacts?where={"_id":{"$in":["56cec38678c3ee45f715b077","56cec37a78c3ee45f715afd6"]},"email":"feugiat.nec.diam@idante.org"} 58 | - http://localhost:8080/posts?where={%22tags%22:{%22$in%22:[%2256d01094b4710c3602715ad2%22]}} 59 | 60 | 61 | # License 62 | 63 | MIT http://mit-license.org 64 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | from eve import Eve 2 | from eve.auth import TokenAuth 3 | from flask import redirect, request, Response 4 | from settings import posts, users 5 | import json 6 | import random 7 | import string 8 | 9 | class RolesAuth(TokenAuth): 10 | def check_auth(self, token, allowed_roles, resource, method): 11 | # use Eve's own db driver; no additional connections/resources are used 12 | accounts = app.data.driver.db['accounts'] 13 | lookup = {'token': token} 14 | if allowed_roles: 15 | # only retrieve a user if his roles match ``allowed_roles`` 16 | lookup['roles'] = {'$in': allowed_roles} 17 | account = accounts.find_one(lookup) 18 | return account 19 | 20 | def add_token(documents): 21 | for document in documents: 22 | document["token"] = (''.join(random.choice(string.ascii_uppercase) 23 | for x in range(10))) 24 | 25 | def filter_hero_image(heroImage): 26 | if 'image' in heroImage: 27 | image = filter_gcs_info(heroImage['image']) 28 | heroImage['image'] = image 29 | return heroImage 30 | 31 | def filter_leading_video(leadingVideo): 32 | if 'video' in leadingVideo: 33 | video = filter_gcs_info(leadingVideo['video']) 34 | leadingVideo['video'] = video 35 | return leadingVideo 36 | 37 | def filter_gcs_info(gcsObj): 38 | if 'gcsDir' in gcsObj: 39 | del gcsObj['gcsDir'] 40 | if 'gcsBucket' in gcsObj: 41 | del gcsObj['gcsBucket'] 42 | if 'filename' in gcsObj: 43 | del gcsObj['filename'] 44 | return gcsObj 45 | 46 | def get_relateds(item, key): 47 | if key in item and item[key]: 48 | headers = dict(request.headers) 49 | tc = app.test_client() 50 | all_relateds = ",".join(map(lambda x: '"' + str(x) + '"',item[key])) 51 | resp = tc.get('meta?where={"_id":{"$in":[' + all_relateds + ']}}', headers=headers) 52 | resp_data = json.loads(resp.get_data().decode()) 53 | result = [] 54 | for i in item[key]: 55 | for j in resp_data['_items']: 56 | if j['_id'] == str(i): 57 | result.append(j) 58 | continue 59 | item[key] = result 60 | # item[key] = resp_data['_items'] 61 | return item 62 | 63 | def before_returning_meta(response): 64 | items = response['_items'] 65 | for item in items: 66 | if 'brief' in item: 67 | del item['brief']['draft'] 68 | del item['brief']['html'] 69 | if 'heroImage' in item: 70 | if item['heroImage'] is not None: 71 | item['heroImage'] = filter_hero_image(item['heroImage']) 72 | return response 73 | 74 | def get_topic(topic_id): 75 | headers = dict(request.headers) 76 | tc = app.test_client() 77 | resp = tc.get('topics/' + str(topic_id) , headers=headers) 78 | resp_data = json.loads(resp.get_data().decode()) 79 | return resp_data 80 | 81 | def filter_post(item): 82 | if 'brief' in item: 83 | del item['brief']['draft'] 84 | del item['brief']['html'] 85 | if 'content' in item: 86 | del item['content']['draft'] 87 | del item['content']['html'] 88 | if 'heroImage' in item: 89 | if type(item['heroImage']) is dict: 90 | item['heroImage'] = filter_hero_image(item['heroImage']) 91 | if 'leading_video' in item: 92 | if type(item['leading_video']) is dict: 93 | item['leading_video'] = filter_leading_video(item['leading_video']) 94 | return item 95 | 96 | def before_returning_posts(response): 97 | items = response['_items'] 98 | for item in items: 99 | item = before_returning_post(item) 100 | return items 101 | 102 | def before_returning_post(response): 103 | item = filter_post(response) 104 | # check if topic object is to be embedded 105 | topics = str(request.args.get('embedded')).find('topics') 106 | 107 | if topics > -1 and 'topics' in item: 108 | item['topics'] = get_topic(item['topics']) 109 | return item 110 | 111 | def filter_topics(items): 112 | for item in items: 113 | item = filter_topic(item) 114 | return items 115 | 116 | def filter_topic(item): 117 | if 'description' in item: 118 | del item['description']['draft'] 119 | del item['description']['apiData'] 120 | if 'team_description' in item: 121 | del item['team_description']['draft'] 122 | del item['team_description']['apiData'] 123 | if 'leading_image' in item: 124 | if type(item['leading_image']) is dict: 125 | item['leading_image'] = filter_hero_image(item['leading_image']) 126 | if 'leading_image_portrait' in item: 127 | if type(item['leading_image_portrait']) is dict: 128 | item['leading_image_portrait'] = filter_hero_image(item['leading_image_portrait']) 129 | if 'leading_video' in item: 130 | if type(item['leading_video']) is dict: 131 | item['leading_video'] = filter_leading_video(item['leading_video']) 132 | return item 133 | 134 | def before_returing_topics(response): 135 | items = response['_items'] 136 | for item in items: 137 | item = before_returning_topic(item) 138 | return response 139 | 140 | def before_returning_topic(response): 141 | item = filter_topic(response) 142 | item = get_relateds(item, 'relateds') 143 | return item 144 | 145 | #app = Eve(auth=RolesAuth) 146 | app = Eve() 147 | app.on_fetched_resource_meta += before_returning_meta 148 | app.on_fetched_resource_posts += before_returning_posts 149 | app.on_fetched_item_posts += before_returning_post 150 | app.on_fetched_resource_topics += before_returing_topics 151 | app.on_fetched_item_topics += before_returning_topic 152 | 153 | if __name__ == '__main__': 154 | app.run(host='0.0.0.0', port=8080, threaded=True, debug=True) 155 | -------------------------------------------------------------------------------- /settings.sample.py: -------------------------------------------------------------------------------- 1 | # MONGO DATABASE SETTINGS 2 | MONGO_HOST = 'localhost' 3 | MONGO_PORT = 27017 4 | MONGO_DBNAME = 'keystone' 5 | 6 | # ALLOW ACTIONS 7 | DEBUG = False 8 | ITEM_METHODS = ['GET', 'PATCH', 'PUT', 'DELETE'] if DEBUG else ['GET'] 9 | 10 | bookmark_schema = { 11 | 'slug': { 12 | 'type': 'string', 13 | }, 14 | 'style': { 15 | 'type': 'string', 16 | }, 17 | 'bookmark': { 18 | 'type': 'string', 19 | }, 20 | 'bookmark_order': { 21 | 'type': 'number', 22 | } 23 | } 24 | 25 | meta_schema = { 26 | 'name': { 27 | 'type': 'string', 28 | }, 29 | 'slug': { 30 | 'type': 'string', 31 | }, 32 | 'title': { 33 | 'type': 'string', 34 | }, 35 | 'subtitle': { 36 | 'type': 'string', 37 | }, 38 | 'brief': { 39 | 'type': 'dict', 40 | 'schema': { 41 | "html": { 42 | "type": "string", 43 | }, 44 | }, 45 | }, 46 | 'topics': { 47 | 'type': 'list', 48 | 'schema': { 49 | 'type': 'objectid', 50 | 'data_relation': { 51 | 'resource': 'topics', 52 | 'field': '_id', 53 | 'embeddable': True 54 | }, 55 | }, 56 | }, 57 | 'heroImage': { 58 | 'type': 'objectid', 59 | 'data_relation': { 60 | 'resource': 'images', 61 | 'field': '_id', 62 | 'embeddable': True 63 | }, 64 | }, 65 | 'categories': { 66 | 'type': 'list', 67 | 'schema': { 68 | 'type': 'objectid', 69 | 'data_relation': { 70 | 'resource': 'postcategories', 71 | 'field': '_id', 72 | 'embeddable': True 73 | }, 74 | }, 75 | }, 76 | 'style': { 77 | 'type': 'string', 78 | }, 79 | 'bookmark': { 80 | 'type': 'string', 81 | }, 82 | 'tags': { 83 | 'type': 'list', 84 | 'schema': { 85 | 'type': 'objectid', 86 | 'data_relation': { 87 | 'resource': 'tags', 88 | 'field': '_id', 89 | 'embeddable': True 90 | }, 91 | }, 92 | }, 93 | 'isFeatured': { 94 | 'type': 'boolean', 95 | }, 96 | 'publishedDate': { 97 | 'type': 'string', 98 | }, 99 | 'og_description': { 100 | 'type': 'string', 101 | }, 102 | } 103 | 104 | post_schema = { 105 | 'name': { 106 | 'type': 'string', 107 | }, 108 | 'slug': { 109 | 'type': 'string', 110 | }, 111 | 'title': { 112 | 'type': 'string', 113 | }, 114 | 'subtitle': { 115 | 'type': 'string', 116 | }, 117 | 'leading_video': { 118 | 'type': 'objectid', 119 | 'data_relation': { 120 | 'resource': 'videos', 121 | 'field': '_id', 122 | 'embeddable': True 123 | }, 124 | }, 125 | 'heroImage': { 126 | 'type': 'objectid', 127 | 'data_relation': { 128 | 'resource': 'images', 129 | 'field': '_id', 130 | 'embeddable': True 131 | }, 132 | }, 133 | 'heroImageSize': { 134 | 'type': 'string', 135 | }, 136 | 'state': { 137 | 'type': 'string', 138 | }, 139 | 'writters': { 140 | 'type': 'list', 141 | 'schema': { 142 | 'type': 'objectid', 143 | 'data_relation': { 144 | 'resource': 'contacts', 145 | 'field': '_id', 146 | 'embeddable': True 147 | }, 148 | }, 149 | }, 150 | 'photographers': { 151 | 'type': 'list', 152 | 'schema': { 153 | 'type': 'objectid', 154 | 'data_relation': { 155 | 'resource': 'contacts', 156 | 'field': '_id', 157 | 'embeddable': True 158 | }, 159 | }, 160 | }, 161 | 'designers': { 162 | 'type': 'list', 163 | 'schema': { 164 | 'type': 'objectid', 165 | 'data_relation': { 166 | 'resource': 'contacts', 167 | 'field': '_id', 168 | 'embeddable': True 169 | }, 170 | }, 171 | }, 172 | 'engineers': { 173 | 'type': 'list', 174 | 'schema': { 175 | 'type': 'objectid', 176 | 'data_relation': { 177 | 'resource': 'contacts', 178 | 'field': '_id', 179 | 'embeddable': True 180 | }, 181 | }, 182 | }, 183 | 'publishedDate': { 184 | 'type': 'string', 185 | }, 186 | 'updatedAt': { 187 | 'type': 'string', 188 | }, 189 | 'categories': { 190 | 'type': 'list', 191 | 'schema': { 192 | 'type': 'objectid', 193 | 'data_relation': { 194 | 'resource': 'postcategories', 195 | 'field': '_id', 196 | 'embeddable': True 197 | }, 198 | }, 199 | }, 200 | 'topics': { 201 | 'type': 'string', 202 | }, 203 | 'tags': { 204 | 'type': 'list', 205 | 'schema': { 206 | 'type': 'objectid', 207 | 'data_relation': { 208 | 'resource': 'tags', 209 | 'field': '_id', 210 | 'embeddable': True 211 | }, 212 | }, 213 | }, 214 | 'style': { 215 | 'type': 'string', 216 | }, 217 | 'bookmark': { 218 | 'type': 'string', 219 | }, 220 | 'bookmark_order': { 221 | 'type': 'number', 222 | }, 223 | 'related_bookmarks': { 224 | 'type': 'list', 225 | 'schema': { 226 | 'type': 'objectid', 227 | 'data_relation': { 228 | 'resource': 'bookmarks', 229 | 'field': '_id', 230 | 'embeddable': True 231 | }, 232 | }, 233 | }, 234 | 'brief': { 235 | 'type': 'dict', 236 | 'schema': { 237 | "html": { 238 | "type": "string", 239 | }, 240 | }, 241 | }, 242 | 'content': { 243 | 'type': 'dict', 244 | 'schema': { 245 | "html": { 246 | "type": "string", 247 | }, 248 | }, 249 | }, 250 | 'relateds': { 251 | 'type': 'list', 252 | 'schema': { 253 | 'type': 'objectid', 254 | 'data_relation': { 255 | 'resource': 'meta', 256 | 'field': '_id', 257 | 'embeddable': True 258 | }, 259 | }, 260 | }, 261 | 'extend_byline': { 262 | 'type': 'string', 263 | }, 264 | 'copyright': { 265 | 'type': 'string', 266 | }, 267 | 'og_title': { 268 | 'type': 'string', 269 | }, 270 | 'isFeatured': { 271 | 'type': 'boolean', 272 | }, 273 | 'og_description': { 274 | 'type': 'string', 275 | }, 276 | 'og_image': { 277 | 'type': 'objectid', 278 | 'data_relation': { 279 | 'resource': 'images', 280 | 'field': '_id', 281 | 'embeddable': True 282 | }, 283 | } 284 | } 285 | 286 | user_schema = { 287 | 'name': { 288 | 'type': 'string', 289 | }, 290 | 'email': { 291 | 'type': 'string', 292 | 'regex': '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', 293 | }, 294 | 'role': { 295 | 'type': 'string', 296 | }, 297 | 'company': { 298 | 'type': 'string', 299 | }, 300 | 'address': { 301 | 'type': 'string', 302 | } 303 | } 304 | 305 | contact_schema = { 306 | 'name': { 307 | 'type': 'string', 308 | }, 309 | 'email': { 310 | 'type': 'string', 311 | 'regex': '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$' 312 | }, 313 | 'homepage': { 314 | 'type': 'string', 315 | }, 316 | 'facebook': { 317 | 'type': 'string', 318 | }, 319 | 'twitter': { 320 | 'type': 'string', 321 | }, 322 | 'instantgram': { 323 | 'type': 'string', 324 | }, 325 | 'bio': { 326 | 'type': 'string', 327 | }, 328 | 'image': { 329 | 'type': 'objectid', 330 | 'data_relation': { 331 | 'resource': 'images', 332 | 'field': '_id', 333 | 'embeddable': True 334 | }, 335 | }, 336 | } 337 | 338 | member_schema = { 339 | 'member_id': { 340 | 'type': 'string', 341 | 'required': True, 342 | }, 343 | 'email': { 344 | 'type': 'string', 345 | 'regex': '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', 346 | }, 347 | 'password': { 348 | 'type': 'string', 349 | 'required': True, 350 | }, 351 | 'country': { 352 | 'type': 'string', 353 | }, 354 | 'city': { 355 | 'type': 'string', 356 | }, 357 | 'address': { 358 | 'type': 'string', 359 | }, 360 | 'zip': { 361 | 'type': 'interger', 362 | }, 363 | 'gender': { 364 | 'type': 'string', 365 | }, 366 | 'state': { 367 | 'type': 'dict', 368 | 'schema': { 369 | 'bookmark': { 370 | 'type': 'list', 371 | 'schema': { 372 | 'type': 'objectid', 373 | 'data_relation': { 374 | 'resource': 'posts', 375 | 'field': '_id', 376 | 'embeddabole': True 377 | }, 378 | }, 379 | }, 380 | 'bookmark_count': { 381 | 'type': 'integer', 382 | }, 383 | 'position': { 384 | 'type': 'string', 385 | } 386 | }, 387 | }, 388 | 'create_date': { 389 | 'type': 'datetime', 390 | } 391 | } 392 | 393 | account_schema = { 394 | 'username': { 395 | 'type': 'string', 396 | 'required': True, 397 | 'unique': True, 398 | }, 399 | 'password': { 400 | 'type': 'string', 401 | 'required': True, 402 | }, 403 | 'roles': { 404 | 'type': 'list', 405 | 'allowed': ['user', 'superuser', 'admin'], 406 | 'required': True, 407 | }, 408 | 'token': { 409 | 'type': 'string', 410 | 'required': True, 411 | } 412 | } 413 | 414 | audios_schema = { 415 | 'description': { 416 | 'type': 'string', 417 | }, 418 | 'audio': { 419 | 'type': 'dict', 420 | 'schema': { 421 | 'filetype': { 422 | 'type': 'string', 423 | }, 424 | 'filename': { 425 | 'type': 'string', 426 | }, 427 | 'originalname': { 428 | 'type': 'string', 429 | }, 430 | 'path': { 431 | 'type': 'string', 432 | }, 433 | 'projectId': { 434 | 'type': 'string', 435 | }, 436 | 'size': { 437 | 'type': 'string', 438 | }, 439 | 'url': { 440 | 'type': 'string', 441 | }, 442 | }, 443 | }, 444 | 'heroImage': { 445 | 'type': 'objectid', 446 | 'data_relation': { 447 | 'resource': 'images', 448 | 'field': '_id', 449 | 'embeddable': True 450 | }, 451 | }, 452 | 'tags': { 453 | 'type': 'list', 454 | 'schema': { 455 | 'type': 'objectid', 456 | 'data_relation': { 457 | 'resource': 'tags', 458 | 'field': '_id', 459 | 'embeddable': True 460 | }, 461 | }, 462 | }, 463 | 'photographer': { 464 | 'type': 'objectid', 465 | 'data_relation': { 466 | 'resource': 'contacts', 467 | 'field': '_id', 468 | 'embeddable': True 469 | }, 470 | }, 471 | } 472 | 473 | video_schema = { 474 | 'title': { 475 | 'type': 'string', 476 | }, 477 | 'video': { 478 | 'type': 'dict', 479 | 'schema': { 480 | 'size': { 481 | 'type': 'string', 482 | }, 483 | 'url': { 484 | 'type': 'string', 485 | }, 486 | }, 487 | }, 488 | 'tags': { 489 | 'type': 'list', 490 | 'schema': { 491 | 'type': 'objectid', 492 | 'data_relation': { 493 | 'resource': 'tags', 494 | 'field': '_id', 495 | 'embeddable': True 496 | }, 497 | }, 498 | } 499 | } 500 | 501 | topics_schema = { 502 | 'name': { 503 | 'type': 'string', 504 | }, 505 | 'title': { 506 | 'type': 'string', 507 | }, 508 | 'subtitle': { 509 | 'type': 'string', 510 | }, 511 | 'headline': { 512 | 'type': 'string', 513 | }, 514 | 'state': { 515 | 'type': 'string', 516 | }, 517 | 'description': { 518 | 'type': 'dict', 519 | 'schema': { 520 | "html": { 521 | "type": "string", 522 | }, 523 | }, 524 | }, 525 | 'team_description': { 526 | 'type': 'dict', 527 | 'schema': { 528 | "html": { 529 | "type": "string", 530 | }, 531 | }, 532 | }, 533 | 'relateds': { 534 | 'type': 'list', 535 | 'schema': { 536 | 'type': 'objectid', 537 | 'data_relation': { 538 | 'resource': 'meta', 539 | 'field': '_id', 540 | 'embeddable': True 541 | }, 542 | }, 543 | }, 544 | 'publishedDate': { 545 | 'type': 'string', 546 | }, 547 | 'leading_image': { 548 | 'type': 'objectid', 549 | 'data_relation': { 550 | 'resource': 'images', 551 | 'field': '_id', 552 | 'embeddable': True 553 | }, 554 | }, 555 | 'leading_image_portrait': { 556 | 'type': 'objectid', 557 | 'data_relation': { 558 | 'resource': 'images', 559 | 'field': '_id', 560 | 'embeddable': True 561 | }, 562 | }, 563 | 'leading_video': { 564 | 'type': 'objectid', 565 | 'data_relation': { 566 | 'resource': 'videos', 567 | 'field': '_id', 568 | 'embeddable': True 569 | }, 570 | }, 571 | } 572 | 573 | image_schema = { 574 | 'photographer': { 575 | 'type': 'objectid', 576 | 'data_relation': { 577 | 'resource': 'contacts', 578 | 'field': '_id', 579 | 'embeddable': True 580 | }, 581 | }, 582 | 'description': { 583 | 'type': 'string', 584 | }, 585 | 'sale': { 586 | 'type': 'Boolean', 587 | }, 588 | 'copyright': { 589 | 'type': 'string', 590 | }, 591 | 'tags': { 592 | 'type': 'list', 593 | 'schema': { 594 | 'type': 'objectid', 595 | 'data_relation': { 596 | 'resource': 'tags', 597 | 'field': '_id', 598 | 'embeddable': True 599 | }, 600 | }, 601 | }, 602 | 'image': { 603 | 'type': 'dict', 604 | 'schema': { 605 | 'artist': { 606 | 'type': 'string', 607 | }, 608 | 'description': { 609 | 'type': 'string', 610 | }, 611 | 'filename': { 612 | 'type': 'string', 613 | }, 614 | 'filetype': { 615 | 'type': 'string', 616 | }, 617 | 'height': { 618 | 'type': 'number', 619 | }, 620 | 'width': { 621 | 'type': 'number', 622 | }, 623 | 'size': { 624 | 'type': 'number', 625 | }, 626 | 'url': { 627 | 'type': 'string', 628 | } 629 | }, 630 | }, 631 | } 632 | 633 | posts = { 634 | 'item_title': 'post', 635 | 'additional_lookup': { 636 | 'url': 'regex("[\w-]+")', 637 | 'field': 'slug' 638 | }, 639 | 'datasource': { 640 | 'source': 'posts', 641 | 'filter': {'state': 'published'}, 642 | }, 643 | 'resource_methods': ['GET'], 644 | 'embedded_fields': ['writters','photographers','designers','engineers','heroImage', 'topics', 'related_bookmarks', 'leading_video', 'og_image', 'tags', 'categories'], 645 | 'cache_control': 'max-age=300,must-revalidate', 646 | 'cache_expires': 300, 647 | 'allow_unknown': False, 648 | 'schema': post_schema 649 | } 650 | 651 | bookmarks = { 652 | 'item_title': 'bookmark', 653 | 'additional_lookup': { 654 | 'url': 'regex("[\w-]+")', 655 | 'field': 'slug' 656 | }, 657 | 'datasource': { 658 | 'source': 'posts', 659 | 'filter': {'state': 'published'}, 660 | }, 661 | 'resource_methods': ['GET'], 662 | 'embedded_fields': [], 663 | 'cache_control': 'max-age=300,must-revalidate', 664 | 'cache_expires': 300, 665 | 'allow_unknown': False, 666 | 'schema': bookmark_schema 667 | } 668 | 669 | meta = { 670 | 'item_title': 'draft', 671 | 'additional_lookup': { 672 | 'url': 'regex("[\w-]+")', 673 | 'field': 'slug' 674 | }, 675 | 'datasource': { 676 | 'source': 'posts', 677 | 'filter': {'state': 'published'}, 678 | }, 679 | 'resource_methods': ['GET'], 680 | 'embedded_fields': ['heroImage', 'categories', 'tags' ], 681 | 'cache_control': 'max-age=300,must-revalidate', 682 | 'cache_expires': 300, 683 | 'allow_unknown': False, 684 | 'schema': meta_schema 685 | } 686 | 687 | drafts = { 688 | 'item_title': 'draft', 689 | 'additional_lookup': { 690 | 'url': 'regex("[\w-]+")', 691 | 'field': 'slug' 692 | }, 693 | 'datasource': { 694 | 'source': 'posts', 695 | 'filter': {'state': 'draft'}, 696 | }, 697 | 'resource_methods': ['GET'], 698 | 'cache_control': 'max-age=300,must-revalidate', 699 | 'cache_expires': 300, 700 | 'allow_unknown': False, 701 | 'schema': post_schema 702 | } 703 | 704 | users = { 705 | 'item_title': 'user', 706 | 'additional_lookup': { 707 | 'url': 'regex(".+")', 708 | 'field': 'name' 709 | }, 710 | 'resource_methods': ['GET'], 711 | 'cache_control': 'max-age=60,must-revalidate', 712 | 'cache_expires': 60, 713 | 'allow_unknown': False, 714 | 'schema': user_schema 715 | } 716 | 717 | members = { 718 | 'item_title': 'member', 719 | 'additional_lookup': { 720 | 'url': 'regex("\w+")', 721 | 'field': 'member_id' 722 | }, 723 | 'resource_methods': ['GET', 'POST'], 724 | 'cache_control': 'max-age=60,must-revalidate', 725 | 'cache_expires': 60, 726 | 'allow_unknown': False, 727 | 'schema': member_schema 728 | } 729 | 730 | contacts = { 731 | 'item_title': 'contact', 732 | 'additional_lookup': { 733 | 'url': 'regex(".+")', 734 | 'field': 'name' 735 | }, 736 | 'resource_methods': ['GET'], 737 | 'cache_control': 'max-age=300,must-revalidate', 738 | 'cache_expires': 300, 739 | 'allow_unknown': True, 740 | 'embedded_fields': ['image'], 741 | 'schema': contact_schema 742 | } 743 | 744 | topics = { 745 | 'item_title': 'topic', 746 | 'additional_lookup': { 747 | 'url': 'regex(".+")', 748 | 'field': 'name' 749 | }, 750 | 'resource_methods': ['GET'], 751 | 'cache_control': 'max-age=3600,must-revalidate', 752 | 'cache_expires': 3600, 753 | 'embedded_fields': ['leading_image','leading_image_portrait','leading_video'], 754 | 'allow_unknown': True, 755 | 'schema': topics_schema 756 | } 757 | 758 | tags = { 759 | 'item_title': 'tag', 760 | 'additional_lookup': { 761 | 'url': 'regex(".+")', 762 | 'field': 'name' 763 | }, 764 | 'resource_methods': ['GET'], 765 | 'cache_control': 'max-age=3600,must-revalidate', 766 | 'cache_expires': 3600, 767 | 'allow_unknown': True, 768 | 'schema': { 769 | 'name': { 770 | 'type': 'string', 771 | } 772 | } 773 | } 774 | 775 | postcategories = { 776 | 'item_title': 'postcategory', 777 | 'additional_lookup': { 778 | 'url': 'regex(".+")', 779 | 'field': 'name' 780 | }, 781 | 'resource_methods': ['GET'], 782 | 'cache_control': 'max-age=3600,must-revalidate', 783 | 'cache_expires': 3600, 784 | 'allow_unknown': True, 785 | 'schema': { 786 | 'name': { 787 | 'type': 'string', 788 | } 789 | } 790 | } 791 | 792 | account = { 793 | 'additional_lookup': { 794 | 'url': 'regex("[\w]+")', 795 | 'field': 'username', 796 | }, 797 | 'resource_methods': ['GET', 'POST'], 798 | 'allowed_roles': ['superuser', 'admin'], 799 | 'cache_control': '', 800 | 'cache_expires': 0, 801 | 'schema': account_schema, 802 | } 803 | 804 | images = { 805 | 'resource_methods': ['GET'], 806 | 'cache_control': 'max-age=3600,must-revalidate', 807 | 'cache_expires': 3600, 808 | 'allow_unknown': False, 809 | 'schema': image_schema, 810 | } 811 | 812 | audios = { 813 | 'resource_methods': ['GET'], 814 | 'cache_control': 'max-age=3600,must-revalidate', 815 | 'cache_expires': 3600, 816 | 'allow_unknown': False, 817 | 'schema': audios_schema, 818 | } 819 | 820 | videos = { 821 | 'resource_methods': ['GET'], 822 | 'cache_control': 'max-age=3600,must-revalidate', 823 | 'cache_expires': 3600, 824 | 'allow_unknown': False, 825 | 'schema': video_schema, 826 | } 827 | 828 | DOMAIN = { 829 | 'bookmarks': bookmarks, 830 | 'posts': posts, 831 | 'drafts': drafts, 832 | 'meta': meta, 833 | 'users': users, 834 | 'members': members, 835 | 'contacts': contacts, 836 | 'tags': tags, 837 | 'topics': topics, 838 | 'postcategories': postcategories, 839 | 'account': account, 840 | 'images': images, 841 | 'audios': audios, 842 | 'videos': videos 843 | } 844 | 845 | XML = False 846 | IF_MATCH = False 847 | X_DOMAINS = '*' 848 | X_HEADERS = ['Content-Type'] 849 | PAGINATION_DEFAULT = 10 850 | --------------------------------------------------------------------------------