-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.py
208 lines (170 loc) · 7.35 KB
/
api.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import logging
import json
import datetime
import layer_cache
from blog.models import *
from spamController import *
from emailController import *
from app import *
from flask import request, Response
from dateutil import parser
from google.appengine.api import memcache
# TODO: Should abstract away this usage
from google.appengine.ext.db import Key
from google.appengine.api import users
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) else None
@application.errorhandler(401)
def custom_401(error):
return Response('You must be logged in', 401, {'WWWAuthenticate':'Basic realm="Login Required"'})
def get_news_items(drafts=False, page=1, order_by=None, tag='', recently_modified=False, year=None):
if 'uncached' in request.args or drafts:
return get_news_items_uncached(drafts, page, order_by, tag, recently_modified, year)
return get_news_items_cached(drafts, page, order_by, tag, recently_modified, year)
@layer_cache.cache_with_key_fxn(lambda drafts, page, order_by, tag, recently_modified, year: "get_news_items_%s_%s_%s_%s_%s_%s" % (drafts, page, order_by, tag, recently_modified, year))
def get_news_items_cached(drafts=False, page=1, order_by=None, tag='', recently_modified=False, year=None):
return get_news_items_uncached(drafts, page, order_by, tag, recently_modified, year)
def get_news_items_uncached(drafts=False, page=1, order_by=None, tag='', recently_modified=False, year=None):
if 'count' in request.args:
count = int(request.args['count'])
else:
count = 2
if page < 1:
page = 1
order_by = '-posted_date'
if recently_modified:
order_by = '-last_modified_date'
page_index = page - 1
if drafts == None:
news_items = NewsItem.all().order(order_by)
elif drafts:
news_items = NewsItem.get_all_drafts(page_index, count, order_by=order_by)
elif tag:
news_items = NewsItem.get_all_by_tag(tag, page_index, count, order_by)
elif year:
news_items = NewsItem.get_all_by_year(year, page_index, count, order_by)
else:
news_items = NewsItem.get_all(page_index, count, order_by=order_by)
news_items = list(news_items)
# Getting tags from the getJsonData function is expensive when fetching a lot
# of news items, so don't get tags when not needed.
if 'noTags' in request.args:
p = [x.jsonDataNoTags for x in news_items]
else:
p = [x.jsonData for x in news_items]
return Response(json.dumps(p, default=dthandler), mimetype='application/json')
def get_news_item(id):
if 'uncached' not in request.args:
return get_news_item_cached(id)
key = Key.from_path('NewsItem', str(id))
news_item = NewsItem.get(key)
return Response(json.dumps(news_item.jsonData, default=dthandler), mimetype='application/json')
@layer_cache.cache_with_key_fxn(lambda id: "get_news_item_%s" % (id))
def get_news_item_cached(id):
news_item = NewsItem.get_by_id(id)
return Response(json.dumps(news_item.jsonData, default=dthandler), mimetype='application/json')
@layer_cache.cache_with_key_fxn(lambda news_item_id: "get_comments_%s" % (news_item_id))
def get_comments(news_item_id):
key = Key.from_path('NewsItem', str(news_item_id))
# Don't use get_by_id here since this can be a draft and that function
# doesn't return draft items
news_item = NewsItem.get(key)
news_item.add_meta_fields()
comments = news_item.sorted_comments()
p = [x.jsonData for x in comments]
return Response(json.dumps(p, default=dthandler), mimetype='application/json')
# Note you can also call this from non admin, but with restricted allowance
# If the user is not authorized, is_public property will be ignored and will sipmly
# be set to false.
def post_comment(news_item_id=None, comment_id=None):
if comment_id:
comment = NewsItemComment.get_by_id(comment_id)
comment.is_public = False
if users.is_current_user_admin():
if ('is_public' in request.json):
comment.is_public = request.json['is_public'];
# Should we report as good?
if ('report_as_good' in request.json):
if report_as_good(comment, request):
logging.info('reported as good!')
else:
logging.info('FAILED TO reported as good!')
# Should we report as spam?
if ('report_as_spam' in request.json):
if report_as_spam(comment, request):
logging.info('reported as spam!')
else:
logging.info('FAILED TO reported as spam!')
else:
comment = NewsItemComment.create()
comment.is_public = False
if news_item_id:
news_item = NewsItem.get_by_id(news_item_id)
comment.news_item = news_item
# TODO: Most of this code can go in the model with a fromJSONData function
comment.name = request.json['name']
comment.email = request.json['email']
comment.body = request.json['body']
comment.homepage = request.json['homepage']
# Only set the posted date and IP if this is not an old comment
if not comment_id:
comment.posted_date = datetime.datetime.now()
comment.poster_ip = request.remote_addr
comment.put()
# If this was a new comment, then send an email about it
if not comment_id:
send_email('[email protected]', 'New comment posted by %s' % comment.name, comment.body)
if comment.is_public:
memcache.flush_all()
return Response(json.dumps(comment.jsonData, default=dthandler), mimetype='application/json')
# Does nothing if the user is not authenticated
def delete_news_item(news_item_id):
if not users.is_current_user_admin():
abort(401)
# Don't use get_by_id here since this can be a draft and that function
# doesn't return draft items
key = Key.from_path('NewsItem', str(news_item_id))
news_item = NewsItem.get(key)
news_item.delete()
return Response(json.dumps({}), mimetype='application/json')
def post_news_item(news_item_id=None):
if not users.is_current_user_admin():
abort(401)
if news_item_id:
key = Key.from_path('NewsItem', str(news_item_id))
news_item = NewsItem.get(key)
news_item.clearTags();
else:
news_item = NewsItem.create()
# TODO: Most of this code can go in the model with a fromJSONData function
news_item.title = request.json['title']
news_item.body = request.json['body']
news_item.draft = request.json['draft']
news_item.posted_date = parser.parse(request.json['posted_date'])
news_item.last_modified_date = parser.parse(request.json['last_modified_date'])
news_item.put();
# Loop through the tags to add them
for tag_name in request.json['tags']:
tag_name = tag_name.strip()
if tag_name == '':
continue
tag = Tag(key_name=tag_name, tag=tag_name)
tag.put()
news_item_tag = NewsItemTag()
news_item_tag.tag = tag.key()
news_item_tag.news_item = news_item.key()
news_item_tag.put()
return Response(json.dumps(news_item.jsonData, default=dthandler), mimetype='application/json')
# Returns an empty array if the user is not authorized to view all comments at once
def get_all_comments():
if not users.is_current_user_admin():
abort(401)
news_item_comments = NewsItemComment.all().order('-posted_date')
p = [x.adminJSONData for x in news_item_comments]
return Response(json.dumps(p), mimetype='application/json')
# Does nothing if the user is not authenticated
def delete_comment(comment_id):
if not users.is_current_user_admin():
abort(401)
comment = NewsItemComment.get_by_id(int(comment_id))
comment.delete();
return Response(json.dumps({}), mimetype='application/json')