6 from werkzeug
.datastructures
import FileStorage
8 from mediagoblin
.media_types
import sniff_media
9 from mediagoblin
.decorators
import oauth_required
10 from mediagoblin
.db
.models
import User
, MediaEntry
, MediaComment
11 from mediagoblin
.tools
.response
import redirect
, json_response
12 from mediagoblin
.meddleware
.csrf
import csrf_exempt
13 from mediagoblin
.submit
.lib
import new_upload_entry
16 def profile(request
, raw
=False):
17 """ This is /api/user/<username>/profile - This will give profile info """
18 user
= request
.matchdict
["username"]
19 requested_user
= User
.query
.filter_by(username
=user
)
21 # check if the user exists
22 if requested_user
is None:
23 error
= "No such 'user' with id '{0}'".format(user
)
24 return json_response({"error": error
}, status
=404)
26 user
= requested_user
[0]
29 return (user
, user
.serialize(request
))
31 # user profiles are public so return information
32 return json_response(user
.serialize(request
))
36 """ This is /api/user/<username> - This will get the user """
37 user
, user_profile
= profile(request
, raw
=True)
39 "nickname": user
.username
,
40 "updated": user
.created
.isoformat(),
41 "published": user
.created
.isoformat(),
42 "profile": user_profile
45 return json_response(data
)
50 """ Endpoint for file uploads """
51 user
= request
.matchdict
["username"]
52 requested_user
= User
.query
.filter_by(username
=user
)
54 if requested_user
is None:
55 error
= "No such 'user' with id '{0}'".format(user
)
56 return json_response({"error": error
}, status
=404)
58 request
.user
= requested_user
[0]
59 if request
.method
== "POST":
60 # Wrap the data in the werkzeug file wrapper
61 mimetype
= request
.headers
.get("Content-Type", "application/octal-stream")
62 filename
= mimetypes
.guess_all_extensions(mimetype
)
63 filename
= 'unknown' + filename
[0] if filename
else filename
64 file_data
= FileStorage(
65 stream
=io
.BytesIO(request
.data
),
71 media_type
, media_manager
= sniff_media(file_data
, filename
)
72 entry
= new_upload_entry(request
.user
)
73 if hasattr(media_manager
, "api_upload_request"):
74 return media_manager
.api_upload_request(request
, file_data
, entry
)
76 return json_response({"error": "Not yet implemented"}, status
=501)
78 return json_response({"error": "Not yet implemented"}, status
=501)
83 """ Handles the user's outbox - /api/user/<username>/feed """
84 user
= request
.matchdict
["username"]
85 requested_user
= User
.query
.filter_by(username
=user
)
87 # check if the user exists
88 if requested_user
is None:
89 error
= "No such 'user' with id '{0}'".format(user
)
90 return json_response({"error": error
}, status
=404)
92 request
.user
= requested_user
[0]
94 data
= json
.loads(request
.data
)
96 data
= {"verb": None, "object": {}}
98 if request
.method
== "POST" and data
["verb"] == "post":
99 obj
= data
.get("object", None)
101 error
= {"error": "Could not find 'object' element."}
102 return json_response(error
, status
=400)
104 if obj
.get("objectType", None) == "comment":
106 media
= int(data
["object"]["inReplyTo"]["id"])
107 comment
= MediaComment(
109 author
=request
.user
.id,
110 content
=data
["object"]["content"]
113 data
= {"verb": "post", "object": comment
.serialize(request
)}
114 return json_response(data
)
116 elif obj
.get("objectType", None) == "image":
117 # Posting an image to the feed
118 # NB: This is currently just handing the image back until we have an
119 # to send the image to the actual feed
121 media_id
= int(data
["object"]["id"])
122 media
= MediaEntry
.query
.filter_by(id=media_id
)
124 error
= "No such 'image' with id '{0}'".format(id=media_id
)
125 return json_response(error
, status
=404)
127 return json_response({
129 "object": media
.serialize(request
)
132 elif obj
.get("objectType", None) is None:
133 # They need to tell us what type of object they're giving us.
134 error
= {"error": "No objectType specified."}
135 return json_response(error
, status
=400)
137 # Oh no! We don't know about this type of object (yet)
138 error_message
= "Unknown object type '{0}'.".format(
139 obj
.get("objectType", None)
142 error
= {"error": error_message
}
143 return json_response(error
, status
=400)
145 elif request
.method
in ["PUT", "POST"] and data
["verb"] == "update":
146 # Check we've got a valid object
147 obj
= data
.get("object", None)
150 error
= {"error": "Could not find 'object' element."}
151 return json_response(error
, status
=400)
153 if "objectType" not in obj
:
154 error
= {"error": "No objectType specified."}
155 return json_response(error
, status
=400)
158 error
= {"error": "Object ID has not been specified."}
159 return json_response(error
, status
=400)
163 # Now try and find object
164 if obj
["objectType"] == "comment":
165 comment
= MediaComment
.query
.filter_by(id=obj_id
)
167 error
= {"error": "No such 'comment' with id '{0}'.".format(obj_id
)}
168 return json_response(error
, status
=400)
171 # TODO: refactor this out to update/setting method on MediaComment
172 if obj
.get("content", None) is not None:
173 comment
.content
= obj
["content"]
178 "object": comment
.serialize(request
),
180 return json_response(activity
)
182 elif obj
["objectType"] == "image":
183 image
= MediaEntry
.query
.filter_by(id=obj_id
)
185 error
= {"error": "No such 'image' with the id '{0}'.".format(obj_id
)}
186 return json_response(error
, status
=400)
190 # TODO: refactor this out to update/setting method on MediaEntry
191 if obj
.get("displayName", None) is not None:
192 image
.title
= obj
["displayName"]
194 if obj
.get("content", None) is not None:
195 image
.description
= obj
["content"]
197 if obj
.get("license", None) is not None:
198 # I think we might need some validation here
199 image
.license
= obj
["license"]
204 "object": image
.serialize(request
),
206 return json_response(activity
)
208 feed_url
= request
.urlgen(
209 "mediagoblin.federation.feed",
210 username
=request
.user
.username
,
215 "displayName": "Activities by {user}@{host}".format(
216 user
=request
.user
.username
,
219 "objectTypes": ["activity"],
235 "author": request
.user
.serialize(request
),
240 # Now lookup the user's feed.
241 for media
in MediaEntry
.query
.all():
242 feed
["items"].append({
244 "object": media
.serialize(request
),
245 "actor": request
.user
.serialize(request
),
246 "content": "{0} posted a picture".format(request
.user
.username
),
249 feed
["items"][-1]["updated"] = feed
["items"][-1]["object"]["updated"]
250 feed
["items"][-1]["published"] = feed
["items"][-1]["object"]["published"]
251 feed
["items"][-1]["url"] = feed
["items"][-1]["object"]["url"]
252 feed
["totalItems"] = len(feed
["items"])
254 return json_response(feed
)
257 def object(request
, raw_obj
=False):
258 """ Lookup for a object type """
259 object_type
= request
.matchdict
["objectType"]
260 uuid
= request
.matchdict
["uuid"]
261 if object_type
not in ["image"]:
262 error
= "Unknown type: {0}".format(object_type
)
263 # not sure why this is 404, maybe ask evan. Maybe 400?
264 return json_response({"error": error
}, status
=404)
266 media
= MediaEntry
.query
.filter_by(slug
=uuid
).first()
268 # no media found with that uuid
269 error
= "Can't find a {0} with ID = {1}".format(object_type
, uuid
)
270 return json_response({"error": error
}, status
=404)
275 return json_response(media
.serialize(request
))
278 def object_comments(request
):
279 """ Looks up for the comments on a object """
280 media
= object(request
, raw_obj
=True)
282 if isinstance(response
, MediaEntry
):
283 comments
= response
.serialize(request
)
284 comments
= comments
.get("replies", {
287 "url": request
.urlgen(
288 "mediagoblin.federation.object.comments",
289 objectType
=media
.objectType
,
295 comments
["displayName"] = "Replies to {0}".format(comments
["url"])
296 comments
["links"] = {
297 "first": comments
["url"],
298 "self": comments
["url"],
300 response
= json_response(comments
)
308 def host_meta(request
):
309 """ This is /.well-known/host-meta - provides URL's to resources on server """
312 # Client registration links
314 "ref": "registration_endpoint",
315 "href": request
.urlgen("mediagoblin.oauth.client_register", qualified
=True),
318 "ref": "http://apinamespace.org/oauth/request_token",
319 "href": request
.urlgen("mediagoblin.oauth.request_token", qualified
=True),
322 "ref": "http://apinamespace.org/oauth/authorize",
323 "href": request
.urlgen("mediagoblin.oauth.authorize", qualified
=True),
326 "ref": "http://apinamespace.org/oauth/access_token",
327 "href": request
.urlgen("mediagoblin.oauth.access_token", qualified
=True),
330 return json_response({"links": links
})
333 """ This is /api/whoami - This is a HTTP redirect to api profile """
334 profile
= request
.urlgen(
335 "mediagoblin.federation.user.profile",
336 username
=request
.user
.username
,
340 return redirect(request
, location
=profile
)