Add location model and migrations
This commit is contained in:
parent
d60d686a14
commit
c0434db469
@ -890,3 +890,40 @@ def revert_username_index(db):
|
|||||||
db.rollback()
|
db.rollback()
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
class Location_V0(declarative_base()):
|
||||||
|
__tablename__ = "core__locations"
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(Unicode)
|
||||||
|
position = Column(MutationDict.as_mutable(JSONEncoded))
|
||||||
|
address = Column(MutationDict.as_mutable(JSONEncoded))
|
||||||
|
|
||||||
|
@RegisterMigration(24, MIGRATIONS)
|
||||||
|
def add_location_model(db):
|
||||||
|
""" Add location model """
|
||||||
|
metadata = MetaData(bind=db.bind)
|
||||||
|
|
||||||
|
# Create location table
|
||||||
|
Location_V0.__table__.create(db.bind)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
# Inspect the tables we need
|
||||||
|
user = inspect_table(metadata, "core__users")
|
||||||
|
collections = inspect_table(metadata, "core__collections")
|
||||||
|
media_entry = inspect_table(metadata, "core__media_entries")
|
||||||
|
media_comments = inspect_table(metadata, "core__media_comments")
|
||||||
|
|
||||||
|
# Now add location support to the various models
|
||||||
|
col = Column("location", Integer, ForeignKey(Location_V0.id))
|
||||||
|
col.create(user)
|
||||||
|
|
||||||
|
col = Column("location", Integer, ForeignKey(Location_V0.id))
|
||||||
|
col.create(collections)
|
||||||
|
|
||||||
|
col = Column("location", Integer, ForeignKey(Location_V0.id))
|
||||||
|
col.create(media_entry)
|
||||||
|
|
||||||
|
col = Column("location", Integer, ForeignKey(Location_V0.id))
|
||||||
|
col.create(media_comments)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
@ -48,6 +48,79 @@ from migrate import changeset
|
|||||||
|
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class Location(Base):
|
||||||
|
""" Represents a physical location """
|
||||||
|
__tablename__ = "core__locations"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(Unicode)
|
||||||
|
|
||||||
|
# GPS coordinates
|
||||||
|
position = Column(MutationDict.as_mutable(JSONEncoded))
|
||||||
|
address = Column(MutationDict.as_mutable(JSONEncoded))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, data, obj):
|
||||||
|
location = cls()
|
||||||
|
location.unserialize(data)
|
||||||
|
location.save()
|
||||||
|
obj.location = location.id
|
||||||
|
return location
|
||||||
|
|
||||||
|
def serialize(self, request):
|
||||||
|
location = {"objectType": "place"}
|
||||||
|
|
||||||
|
if self.name is not None:
|
||||||
|
location["name"] = self.name
|
||||||
|
|
||||||
|
if self.position:
|
||||||
|
location["position"] = self.position
|
||||||
|
|
||||||
|
if self.address:
|
||||||
|
location["address"] = self.address
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
|
def unserialize(self, data):
|
||||||
|
if "name" in data:
|
||||||
|
self.name = data["name"]
|
||||||
|
|
||||||
|
self.position = {}
|
||||||
|
self.address = {}
|
||||||
|
|
||||||
|
# nicer way to do this?
|
||||||
|
if "position" in data:
|
||||||
|
# TODO: deal with ISO 9709 formatted string as position
|
||||||
|
if "altitude" in data["position"]:
|
||||||
|
self.position["altitude"] = data["position"]["altitude"]
|
||||||
|
|
||||||
|
if "direction" in data["position"]:
|
||||||
|
self.position["direction"] = data["position"]["direction"]
|
||||||
|
|
||||||
|
if "longitude" in data["position"]:
|
||||||
|
self.position["longitude"] = data["position"]["longitude"]
|
||||||
|
|
||||||
|
if "latitude" in data["position"]:
|
||||||
|
self.position["latitude"] = data["position"]["latitude"]
|
||||||
|
|
||||||
|
if "address" in data:
|
||||||
|
if "formatted" in data["address"]:
|
||||||
|
self.address["formatted"] = data["address"]["formatted"]
|
||||||
|
|
||||||
|
if "streetAddress" in data["address"]:
|
||||||
|
self.address["streetAddress"] = data["address"]["streetAddress"]
|
||||||
|
|
||||||
|
if "locality" in data["address"]:
|
||||||
|
self.address["locality"] = data["address"]["locality"]
|
||||||
|
|
||||||
|
if "region" in data["address"]:
|
||||||
|
self.address["region"] = data["address"]["region"]
|
||||||
|
|
||||||
|
if "postalCode" in data["address"]:
|
||||||
|
self.address["postalCode"] = data["addresss"]["postalCode"]
|
||||||
|
|
||||||
|
if "country" in data["address"]:
|
||||||
|
self.address["country"] = data["address"]["country"]
|
||||||
|
|
||||||
|
|
||||||
class User(Base, UserMixin):
|
class User(Base, UserMixin):
|
||||||
@ -75,6 +148,8 @@ class User(Base, UserMixin):
|
|||||||
bio = Column(UnicodeText) # ??
|
bio = Column(UnicodeText) # ??
|
||||||
uploaded = Column(Integer, default=0)
|
uploaded = Column(Integer, default=0)
|
||||||
upload_limit = Column(Integer)
|
upload_limit = Column(Integer)
|
||||||
|
location = Column(Integer, ForeignKey("core__locations.id"))
|
||||||
|
get_location = relationship("Location", lazy="joined")
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
# plugin data would be in a separate model
|
# plugin data would be in a separate model
|
||||||
@ -177,9 +252,18 @@ class User(Base, UserMixin):
|
|||||||
user.update({"summary": self.bio})
|
user.update({"summary": self.bio})
|
||||||
if self.url:
|
if self.url:
|
||||||
user.update({"url": self.url})
|
user.update({"url": self.url})
|
||||||
|
if self.location:
|
||||||
|
user.update({"location": self.get_location.seralize(request)})
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
def unserialize(self, data):
|
||||||
|
if "summary" in data:
|
||||||
|
self.bio = data["summary"]
|
||||||
|
|
||||||
|
if "location" in data:
|
||||||
|
Location.create(data, self)
|
||||||
|
|
||||||
class Client(Base):
|
class Client(Base):
|
||||||
"""
|
"""
|
||||||
Model representing a client - Used for API Auth
|
Model representing a client - Used for API Auth
|
||||||
@ -263,6 +347,8 @@ class MediaEntry(Base, MediaEntryMixin):
|
|||||||
# or use sqlalchemy.types.Enum?
|
# or use sqlalchemy.types.Enum?
|
||||||
license = Column(Unicode)
|
license = Column(Unicode)
|
||||||
file_size = Column(Integer, default=0)
|
file_size = Column(Integer, default=0)
|
||||||
|
location = Column(Integer, ForeignKey("core__locations.id"))
|
||||||
|
get_location = relationship("Location", lazy="joined")
|
||||||
|
|
||||||
fail_error = Column(Unicode)
|
fail_error = Column(Unicode)
|
||||||
fail_metadata = Column(JSONEncoded)
|
fail_metadata = Column(JSONEncoded)
|
||||||
@ -477,6 +563,9 @@ class MediaEntry(Base, MediaEntryMixin):
|
|||||||
if self.license:
|
if self.license:
|
||||||
context["license"] = self.license
|
context["license"] = self.license
|
||||||
|
|
||||||
|
if self.location:
|
||||||
|
context["location"] = self.get_location.serialize(request)
|
||||||
|
|
||||||
if show_comments:
|
if show_comments:
|
||||||
comments = [comment.serialize(request) for comment in self.get_comments()]
|
comments = [comment.serialize(request) for comment in self.get_comments()]
|
||||||
total = len(comments)
|
total = len(comments)
|
||||||
@ -504,6 +593,9 @@ class MediaEntry(Base, MediaEntryMixin):
|
|||||||
if "license" in data:
|
if "license" in data:
|
||||||
self.license = data["license"]
|
self.license = data["license"]
|
||||||
|
|
||||||
|
if "location" in data:
|
||||||
|
Licence.create(data["location"], self)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class FileKeynames(Base):
|
class FileKeynames(Base):
|
||||||
@ -629,6 +721,8 @@ class MediaComment(Base, MediaCommentMixin):
|
|||||||
author = Column(Integer, ForeignKey(User.id), nullable=False)
|
author = Column(Integer, ForeignKey(User.id), nullable=False)
|
||||||
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||||
content = Column(UnicodeText, nullable=False)
|
content = Column(UnicodeText, nullable=False)
|
||||||
|
location = Column(Integer, ForeignKey("core__locations.id"))
|
||||||
|
get_location = relationship("Location", lazy="joined")
|
||||||
|
|
||||||
# Cascade: Comments are owned by their creator. So do the full thing.
|
# Cascade: Comments are owned by their creator. So do the full thing.
|
||||||
# lazy=dynamic: People might post a *lot* of comments,
|
# lazy=dynamic: People might post a *lot* of comments,
|
||||||
@ -663,6 +757,9 @@ class MediaComment(Base, MediaCommentMixin):
|
|||||||
"author": author.serialize(request)
|
"author": author.serialize(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.location:
|
||||||
|
context["location"] = self.get_location.seralize(request)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def unserialize(self, data):
|
def unserialize(self, data):
|
||||||
@ -689,6 +786,10 @@ class MediaComment(Base, MediaCommentMixin):
|
|||||||
|
|
||||||
self.media_entry = media.id
|
self.media_entry = media.id
|
||||||
self.content = data["content"]
|
self.content = data["content"]
|
||||||
|
|
||||||
|
if "location" in data:
|
||||||
|
Location.create(data["location"], self)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -707,6 +808,9 @@ class Collection(Base, CollectionMixin):
|
|||||||
index=True)
|
index=True)
|
||||||
description = Column(UnicodeText)
|
description = Column(UnicodeText)
|
||||||
creator = Column(Integer, ForeignKey(User.id), nullable=False)
|
creator = Column(Integer, ForeignKey(User.id), nullable=False)
|
||||||
|
location = Column(Integer, ForeignKey("core__locations.id"))
|
||||||
|
get_location = relationship("Location", lazy="joined")
|
||||||
|
|
||||||
# TODO: No of items in Collection. Badly named, can we migrate to num_items?
|
# TODO: No of items in Collection. Badly named, can we migrate to num_items?
|
||||||
items = Column(Integer, default=0)
|
items = Column(Integer, default=0)
|
||||||
|
|
||||||
@ -869,9 +973,8 @@ class ProcessingNotification(Notification):
|
|||||||
'polymorphic_identity': 'processing_notification'
|
'polymorphic_identity': 'processing_notification'
|
||||||
}
|
}
|
||||||
|
|
||||||
with_polymorphic(
|
# the with_polymorphic call has been moved to the bottom above MODELS
|
||||||
Notification,
|
# this is because it causes conflicts with relationship calls.
|
||||||
[ProcessingNotification, CommentNotification])
|
|
||||||
|
|
||||||
class ReportBase(Base):
|
class ReportBase(Base):
|
||||||
"""
|
"""
|
||||||
@ -1054,13 +1157,19 @@ class PrivilegeUserAssociation(Base):
|
|||||||
ForeignKey(Privilege.id),
|
ForeignKey(Privilege.id),
|
||||||
primary_key=True)
|
primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
|
with_polymorphic(
|
||||||
|
Notification,
|
||||||
|
[ProcessingNotification, CommentNotification])
|
||||||
|
|
||||||
MODELS = [
|
MODELS = [
|
||||||
User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
|
User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
|
||||||
MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData,
|
MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData,
|
||||||
Notification, CommentNotification, ProcessingNotification, Client,
|
Notification, CommentNotification, ProcessingNotification, Client,
|
||||||
CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan,
|
CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan,
|
||||||
Privilege, PrivilegeUserAssociation,
|
Privilege, PrivilegeUserAssociation,
|
||||||
RequestToken, AccessToken, NonceTimestamp]
|
RequestToken, AccessToken, NonceTimestamp,
|
||||||
|
Location]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Foundations are the default rows that are created immediately after the tables
|
Foundations are the default rows that are created immediately after the tables
|
||||||
|
@ -61,6 +61,7 @@ class EditProfileForm(wtforms.Form):
|
|||||||
[wtforms.validators.Optional(),
|
[wtforms.validators.Optional(),
|
||||||
wtforms.validators.URL(message=_("This address contains errors"))])
|
wtforms.validators.URL(message=_("This address contains errors"))])
|
||||||
|
|
||||||
|
location = wtforms.TextField(_('Hometown'))
|
||||||
|
|
||||||
class EditAccountForm(wtforms.Form):
|
class EditAccountForm(wtforms.Form):
|
||||||
wants_comment_notification = wtforms.BooleanField(
|
wants_comment_notification = wtforms.BooleanField(
|
||||||
|
@ -45,7 +45,7 @@ from mediagoblin.tools.text import (
|
|||||||
convert_to_tag_list_of_dicts, media_tags_as_string)
|
convert_to_tag_list_of_dicts, media_tags_as_string)
|
||||||
from mediagoblin.tools.url import slugify
|
from mediagoblin.tools.url import slugify
|
||||||
from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
|
from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
|
||||||
from mediagoblin.db.models import User
|
from mediagoblin.db.models import User, Location
|
||||||
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
|
||||||
@ -200,14 +200,29 @@ def edit_profile(request, url_user=None):
|
|||||||
|
|
||||||
user = url_user
|
user = url_user
|
||||||
|
|
||||||
|
# Get the location name
|
||||||
|
if user.location is None:
|
||||||
|
location = ""
|
||||||
|
else:
|
||||||
|
location = user.get_location.name
|
||||||
|
|
||||||
form = forms.EditProfileForm(request.form,
|
form = forms.EditProfileForm(request.form,
|
||||||
url=user.url,
|
url=user.url,
|
||||||
bio=user.bio)
|
bio=user.bio,
|
||||||
|
location=location)
|
||||||
|
|
||||||
if request.method == 'POST' and form.validate():
|
if request.method == 'POST' and form.validate():
|
||||||
user.url = unicode(form.url.data)
|
user.url = unicode(form.url.data)
|
||||||
user.bio = unicode(form.bio.data)
|
user.bio = unicode(form.bio.data)
|
||||||
|
|
||||||
|
# Save location
|
||||||
|
if form.location.data and user.location is None:
|
||||||
|
user.get_location = Location(name=unicode(form.location.data))
|
||||||
|
elif form.location.data:
|
||||||
|
location = user.get_location.name
|
||||||
|
location.name = unicode(form.location.data)
|
||||||
|
location.save()
|
||||||
|
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
messages.add_message(request,
|
messages.add_message(request,
|
||||||
@ -450,7 +465,7 @@ def edit_metadata(request, media):
|
|||||||
json_ld_metadata = compact_and_validate(metadata_dict)
|
json_ld_metadata = compact_and_validate(metadata_dict)
|
||||||
media.media_metadata = json_ld_metadata
|
media.media_metadata = json_ld_metadata
|
||||||
media.save()
|
media.save()
|
||||||
return redirect_obj(request, media)
|
return redirect_obj(request, media)
|
||||||
|
|
||||||
if len(form.media_metadata) == 0:
|
if len(form.media_metadata) == 0:
|
||||||
for identifier, value in media.media_metadata.iteritems():
|
for identifier, value in media.media_metadata.iteritems():
|
||||||
|
@ -70,14 +70,14 @@ def profile_endpoint(request):
|
|||||||
def user_endpoint(request):
|
def user_endpoint(request):
|
||||||
""" This is /api/user/<username> - This will get the user """
|
""" This is /api/user/<username> - This will get the user """
|
||||||
user, user_profile = get_profile(request)
|
user, user_profile = get_profile(request)
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
username = request.matchdict["username"]
|
username = request.matchdict["username"]
|
||||||
return json_error(
|
return json_error(
|
||||||
"No such 'user' with username '{0}'".format(username),
|
"No such 'user' with username '{0}'".format(username),
|
||||||
status=404
|
status=404
|
||||||
)
|
)
|
||||||
|
|
||||||
return json_response({
|
return json_response({
|
||||||
"nickname": user.username,
|
"nickname": user.username,
|
||||||
"updated": user.created.isoformat(),
|
"updated": user.created.isoformat(),
|
||||||
@ -207,6 +207,11 @@ def feed_endpoint(request):
|
|||||||
"Invalid 'image' with id '{0}'".format(media_id)
|
"Invalid 'image' with id '{0}'".format(media_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Add location if one exists
|
||||||
|
if "location" in data:
|
||||||
|
Location.create(data["location"], self)
|
||||||
|
|
||||||
media.save()
|
media.save()
|
||||||
api_add_to_feed(request, media)
|
api_add_to_feed(request, media)
|
||||||
|
|
||||||
@ -302,6 +307,15 @@ def feed_endpoint(request):
|
|||||||
"object": image.serialize(request),
|
"object": image.serialize(request),
|
||||||
}
|
}
|
||||||
return json_response(activity)
|
return json_response(activity)
|
||||||
|
elif obj["objectType"] == "person":
|
||||||
|
# check this is the same user
|
||||||
|
if "id" not in obj or obj["id"] != requested_user.id:
|
||||||
|
return json_error(
|
||||||
|
"Incorrect user id, unable to update"
|
||||||
|
)
|
||||||
|
|
||||||
|
requested_user.unserialize(obj)
|
||||||
|
requested_user.save()
|
||||||
|
|
||||||
elif request.method != "GET":
|
elif request.method != "GET":
|
||||||
return json_error(
|
return json_error(
|
||||||
|
@ -13,5 +13,61 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import json
|
||||||
|
|
||||||
|
from sqlalchemy import MetaData, Column, ForeignKey
|
||||||
|
|
||||||
|
from mediagoblin.db.migration_tools import RegisterMigration, inspect_table
|
||||||
|
|
||||||
|
|
||||||
MIGRATIONS = {}
|
MIGRATIONS = {}
|
||||||
|
|
||||||
|
@RegisterMigration(1, MIGRATIONS)
|
||||||
|
def remove_gps_from_image(db):
|
||||||
|
"""
|
||||||
|
This will remove GPS coordinates from the image model to put them
|
||||||
|
on the new Location model.
|
||||||
|
"""
|
||||||
|
metadata = MetaData(bind=db.bind)
|
||||||
|
image_table = inspect_table(metadata, "image__mediadata")
|
||||||
|
location_table = inspect_table(metadata, "core__locations")
|
||||||
|
media_entires_table = inspect_table(metadata, "core__media_entries")
|
||||||
|
|
||||||
|
# First do the data migration
|
||||||
|
for row in db.execute(image_table.select()):
|
||||||
|
fields = {
|
||||||
|
"longitude": row.gps_longitude,
|
||||||
|
"latitude": row.gps_latitude,
|
||||||
|
"altitude": row.gps_altitude,
|
||||||
|
"direction": row.gps_direction,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove empty values
|
||||||
|
for k, v in fields.items():
|
||||||
|
if v is None:
|
||||||
|
del fields[k]
|
||||||
|
|
||||||
|
# No point in adding empty locations
|
||||||
|
if not fields:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# JSONEncoded is actually a string field just json.dumped
|
||||||
|
# without the ORM we're responsible for that.
|
||||||
|
fields = json.dumps(fields)
|
||||||
|
|
||||||
|
location = db.execute(location_table.insert().values(position=fields))
|
||||||
|
|
||||||
|
# now store the new location model on Image
|
||||||
|
db.execute(media_entires_table.update().values(
|
||||||
|
location=location.inserted_primary_key[0]
|
||||||
|
).where(media_entires_table.c.id==row.media_entry))
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
# All that data has been migrated across lets remove the fields
|
||||||
|
image_table.columns["gps_longitude"].drop()
|
||||||
|
image_table.columns["gps_latitude"].drop()
|
||||||
|
image_table.columns["gps_altitude"].drop()
|
||||||
|
image_table.columns["gps_direction"].drop()
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
@ -39,10 +39,6 @@ class ImageData(Base):
|
|||||||
width = Column(Integer)
|
width = Column(Integer)
|
||||||
height = Column(Integer)
|
height = Column(Integer)
|
||||||
exif_all = Column(JSONEncoded)
|
exif_all = Column(JSONEncoded)
|
||||||
gps_longitude = Column(Float)
|
|
||||||
gps_latitude = Column(Float)
|
|
||||||
gps_altitude = Column(Float)
|
|
||||||
gps_direction = Column(Float)
|
|
||||||
|
|
||||||
|
|
||||||
DATA_MODEL = ImageData
|
DATA_MODEL = ImageData
|
||||||
|
@ -23,6 +23,7 @@ import logging
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from mediagoblin import mg_globals as mgg
|
from mediagoblin import mg_globals as mgg
|
||||||
|
from mediagoblin.db.models import Location
|
||||||
from mediagoblin.processing import (
|
from mediagoblin.processing import (
|
||||||
BadMediaFail, FilenameBuilder,
|
BadMediaFail, FilenameBuilder,
|
||||||
MediaProcessor, ProcessingManager,
|
MediaProcessor, ProcessingManager,
|
||||||
@ -231,8 +232,7 @@ class CommonImageProcessor(MediaProcessor):
|
|||||||
self.entry.media_data_init(exif_all=exif_all)
|
self.entry.media_data_init(exif_all=exif_all)
|
||||||
|
|
||||||
if len(gps_data):
|
if len(gps_data):
|
||||||
for key in list(gps_data.keys()):
|
Location.create({"position": gps_data}, self.entry)
|
||||||
gps_data['gps_' + key] = gps_data.pop(key)
|
|
||||||
self.entry.media_data_init(**gps_data)
|
self.entry.media_data_init(**gps_data)
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,13 +21,13 @@ PLUGIN_DIR = os.path.dirname(__file__)
|
|||||||
|
|
||||||
def setup_plugin():
|
def setup_plugin():
|
||||||
config = pluginapi.get_config('mediagoblin.plugins.geolocation')
|
config = pluginapi.get_config('mediagoblin.plugins.geolocation')
|
||||||
|
|
||||||
# Register the template path.
|
# Register the template path.
|
||||||
pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
|
pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
|
||||||
|
|
||||||
pluginapi.register_template_hooks(
|
pluginapi.register_template_hooks(
|
||||||
{"image_sideinfo": "mediagoblin/plugins/geolocation/map.html",
|
{"location_info": "mediagoblin/plugins/geolocation/map.html",
|
||||||
"image_head": "mediagoblin/plugins/geolocation/map_js_head.html"})
|
"location_head": "mediagoblin/plugins/geolocation/map_js_head.html"})
|
||||||
|
|
||||||
|
|
||||||
hooks = {
|
hooks = {
|
||||||
|
@ -17,14 +17,13 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block geolocation_map %}
|
{% block geolocation_map %}
|
||||||
{% if media.media_data.gps_latitude is defined
|
{% if model.location
|
||||||
and media.media_data.gps_latitude
|
and model.get_location.position
|
||||||
and media.media_data.gps_longitude is defined
|
and model.get_location.position.latitude
|
||||||
and media.media_data.gps_longitude %}
|
and model.get_location.position.longitude %}
|
||||||
<h3>{% trans %}Location{% endtrans %}</h3>
|
|
||||||
<div>
|
<div>
|
||||||
{%- set lon = media.media_data.gps_longitude %}
|
{%- set lon = model.get_location.position.longitude %}
|
||||||
{%- set lat = media.media_data.gps_latitude %}
|
{%- set lat = model.get_location.position.latitude %}
|
||||||
{%- set osm_url = "http://openstreetmap.org/?mlat={lat}&mlon={lon}".format(lat=lat, lon=lon) %}
|
{%- set osm_url = "http://openstreetmap.org/?mlat={lat}&mlon={lon}".format(lat=lat, lon=lon) %}
|
||||||
<div id="tile-map" style="width: 100%; height: 196px;">
|
<div id="tile-map" style="width: 100%; height: 196px;">
|
||||||
<input type="hidden" id="gps-longitude"
|
<input type="hidden" id="gps-longitude"
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
src="{{ request.staticdirect('/js/keyboard_navigation.js') }}"></script>
|
src="{{ request.staticdirect('/js/keyboard_navigation.js') }}"></script>
|
||||||
|
|
||||||
|
{% template_hook("location_head") %}
|
||||||
{% template_hook("media_head") %}
|
{% template_hook("media_head") %}
|
||||||
{% endblock mediagoblin_head %}
|
{% endblock mediagoblin_head %}
|
||||||
{% block mediagoblin_content %}
|
{% block mediagoblin_content %}
|
||||||
@ -231,6 +232,8 @@
|
|||||||
{% block mediagoblin_sidebar %}
|
{% block mediagoblin_sidebar %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{%- set model = media %}
|
||||||
|
{% template_hook("location_info") %}
|
||||||
{% template_hook("media_sideinfo") %}
|
{% template_hook("media_sideinfo") %}
|
||||||
|
|
||||||
</div><!--end media_sidebar-->
|
</div><!--end media_sidebar-->
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
{%- trans username=user.username %}{{ username }}'s profile{% endtrans -%}
|
{%- trans username=user.username %}{{ username }}'s profile{% endtrans -%}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
{% if not user.url and not user.bio %}
|
{% if not user.url and not user.bio and not user.location %}
|
||||||
{% if request.user and (request.user.id == user.id) %}
|
{% if request.user and (request.user.id == user.id) %}
|
||||||
<div class="profile_sidebar empty_space">
|
<div class="profile_sidebar empty_space">
|
||||||
<p>
|
<p>
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{% block mediagoblin_head %}
|
||||||
|
{% template_hook("location_head") %}
|
||||||
|
{% endblock mediagoblin_head %}
|
||||||
|
|
||||||
{% block profile_content -%}
|
{% block profile_content -%}
|
||||||
{% if user.bio %}
|
{% if user.bio %}
|
||||||
{% autoescape False %}
|
{% autoescape False %}
|
||||||
@ -27,4 +31,12 @@
|
|||||||
<a href="{{ user.url }}">{{ user.url }}</a>
|
<a href="{{ user.url }}">{{ user.url }}</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if user.location %}
|
||||||
|
{%- set model = user %}
|
||||||
|
<h3>{% trans %}Location{% endtrans %}</h3>
|
||||||
|
{% if model.get_location.name %}
|
||||||
|
<p>{{ model.get_location.name }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% template_hook("location_info") %}
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -359,7 +359,7 @@ class TestSubmission:
|
|||||||
def test_media_data(self):
|
def test_media_data(self):
|
||||||
self.check_normal_upload(u"With GPS data", GPS_JPG)
|
self.check_normal_upload(u"With GPS data", GPS_JPG)
|
||||||
media = self.check_media(None, {"title": u"With GPS data"}, 1)
|
media = self.check_media(None, {"title": u"With GPS data"}, 1)
|
||||||
assert media.media_data.gps_latitude == 59.336666666666666
|
assert media.get_location.position["latitude"] == 59.336666666666666
|
||||||
|
|
||||||
def test_processing(self):
|
def test_processing(self):
|
||||||
public_store_dir = mg_globals.global_config[
|
public_store_dir = mg_globals.global_config[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user