basic tagging
This commit is contained in:
parent
1ff3e2106b
commit
018faecc3a
|
@ -138,6 +138,36 @@ class PhotoView(object):
|
||||||
|
|
||||||
# yield "viewing {}".format(uuid)
|
# yield "viewing {}".format(uuid)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def tag(self, uuid):
|
||||||
|
s = self.master.session()
|
||||||
|
photo = s.query(PhotoSet).filter(PhotoSet.uuid == uuid).first()
|
||||||
|
alltags = s.query(Tag).order_by(Tag.title).all()
|
||||||
|
yield self.master.tpl.get_template("photo_tag.html").render(image=photo, alltags=alltags)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def tag_create(self, uuid, tag):
|
||||||
|
# TODO validate uuid ?
|
||||||
|
s = self.master.session()
|
||||||
|
s.add(Tag(title=tag)) # TODO slug
|
||||||
|
# TODO generate slug now or in model?
|
||||||
|
s.commit()
|
||||||
|
raise cherrypy.HTTPRedirect('/photo/{}/tag'.format(uuid), 302)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def tag_add(self, uuid, tag):
|
||||||
|
# TODO validate uuid ?
|
||||||
|
# TODO validate tag ?
|
||||||
|
s = self.master.session()
|
||||||
|
tag = s.query(Tag).filter(Tag.uuid == tag).first()
|
||||||
|
item = s.query(PhotoSet).filter(PhotoSet.uuid == uuid).first()
|
||||||
|
s.add(TagItem(tag_id=tag.id, set_id=item.id))
|
||||||
|
try:
|
||||||
|
s.commit()
|
||||||
|
except IntegrityError: # tag already applied
|
||||||
|
pass
|
||||||
|
raise cherrypy.HTTPRedirect('/photo/{}/tag'.format(uuid), 302)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import argparse
|
import argparse
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from sqlalchemy import Column, Integer, String, DateTime, Unicode, DECIMAL, ForeignKey
|
from sqlalchemy import Column, Integer, String, DateTime, Unicode, DECIMAL, ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.schema import UniqueConstraint
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from datetime import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,12 +13,13 @@ class PhotoSet(Base):
|
||||||
__tablename__ = 'photos'
|
__tablename__ = 'photos'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
uuid = Column(Unicode, default=lambda: str(uuid.uuid4()))
|
uuid = Column(Unicode, unique=True, default=lambda: str(uuid.uuid4()))
|
||||||
date = Column(DateTime)
|
date = Column(DateTime)
|
||||||
lat = Column(DECIMAL(precision=11))
|
lat = Column(DECIMAL(precision=11))
|
||||||
lon = Column(DECIMAL(precision=11))
|
lon = Column(DECIMAL(precision=11))
|
||||||
|
|
||||||
files = relationship("Photo", back_populates="set")
|
files = relationship("Photo", back_populates="set")
|
||||||
|
tags = relationship("TagItem", back_populates="set")
|
||||||
|
|
||||||
title = Column(String)
|
title = Column(String)
|
||||||
description = Column(String)
|
description = Column(String)
|
||||||
|
@ -27,7 +30,7 @@ class Photo(Base):
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
set_id = Column(Integer, ForeignKey("photos.id"))
|
set_id = Column(Integer, ForeignKey("photos.id"))
|
||||||
uuid = Column(Unicode, default=lambda: str(uuid.uuid4()))
|
uuid = Column(Unicode, unique=True, default=lambda: str(uuid.uuid4()))
|
||||||
|
|
||||||
set = relationship("PhotoSet", back_populates="files", foreign_keys=[set_id])
|
set = relationship("PhotoSet", back_populates="files", foreign_keys=[set_id])
|
||||||
|
|
||||||
|
@ -44,11 +47,11 @@ class Tag(Base):
|
||||||
__tablename__ = 'tags'
|
__tablename__ = 'tags'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
uuid = Column(Unicode, default=lambda: str(uuid.uuid4()))
|
uuid = Column(Unicode, unique=True, default=lambda: str(uuid.uuid4()))
|
||||||
created = Column(DateTime)
|
created = Column(DateTime, default=lambda: datetime.now())
|
||||||
modified = Column(DateTime)
|
modified = Column(DateTime, default=lambda: datetime.now())
|
||||||
title = Column(String)
|
title = Column(String, unique=True)
|
||||||
slug = Column(String)
|
slug = Column(String, unique=True)
|
||||||
description = Column(String)
|
description = Column(String)
|
||||||
|
|
||||||
entries = relationship("TagItem", back_populates="tag")
|
entries = relationship("TagItem", back_populates="tag")
|
||||||
|
@ -59,8 +62,10 @@ class TagItem(Base):
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
tag_id = Column(Integer, ForeignKey("tags.id"))
|
tag_id = Column(Integer, ForeignKey("tags.id"))
|
||||||
|
set_id = Column(Integer, ForeignKey("photos.id"))
|
||||||
|
order = Column(Integer, default=0)
|
||||||
|
|
||||||
tag = relationship("Tag", back_populates="entries", foreign_keys=[tag_id])
|
tag = relationship("Tag", back_populates="entries", foreign_keys=[tag_id])
|
||||||
|
set = relationship("PhotoSet", back_populates="tags", foreign_keys=[set_id])
|
||||||
|
|
||||||
item_uuid = Column(String, unique=True)
|
UniqueConstraint(tag_id, set_id)
|
||||||
order = Column(Integer, default=0)
|
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@linkcolor: #1b98f8;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #1b98f8;
|
color: @linkcolor;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layout, #nav, #list, #main {
|
#layout, #nav, #list, #main {
|
||||||
|
@ -204,4 +207,35 @@ a {
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.photo-tags {
|
||||||
|
h2 a {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-tagging {
|
||||||
|
img {
|
||||||
|
float: left;
|
||||||
|
padding: 0px 20px 20px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-picker {
|
||||||
|
ul {
|
||||||
|
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
input.submit-link {
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
color: @linkcolor;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,15 @@
|
||||||
{{ img.path | basename }}
|
{{ img.path | basename }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{ img.size | filesizeformat }} - {{ img.format }}
|
{{ img.size | filesizeformat }} - {{ img.width }} x {{ img.height }}
|
||||||
|
</div>
|
||||||
|
{% if img.orientation > 0 %}
|
||||||
|
<div>
|
||||||
|
Rotation: {{ img.orientation * 90 }}°
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
{{ img.format }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="/download/one/{{ img.uuid }}">download</a>
|
<a href="/download/one/{{ img.uuid }}">download</a>
|
||||||
|
@ -47,6 +55,16 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="photo-tags">
|
||||||
|
<h2>Tags <a href="/photo/{{ image.uuid }}/tag">add</a></h2>
|
||||||
|
<ul class="tags-picker">
|
||||||
|
{% for tagi in image.tags %}
|
||||||
|
<li>
|
||||||
|
<a href="/tags/{{ tagi.tag.uuid }}">{{ tagi.tag.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
{% set title = "Placeholder Title" %}
|
||||||
|
{% set subtitle = image.uuid %}
|
||||||
|
|
||||||
|
{% include "page-top.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="photo-tagging pure-g">
|
||||||
|
<div class="current-tags pure-u-1-3">
|
||||||
|
<h2>Current Tags</h2>
|
||||||
|
<a href="/photo/{{ image.uuid }}">
|
||||||
|
<img src="/thumb/set/small/{{ image.uuid }}.jpg" />
|
||||||
|
</a>
|
||||||
|
<ul class="tags-picker">
|
||||||
|
{% for tagi in image.tags %}
|
||||||
|
<li>
|
||||||
|
<a href="/tags/{{ tagi.tag.uuid }}">{{ tagi.tag.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="all-tags pure-u-1-3">
|
||||||
|
<h2>All tags</h2>
|
||||||
|
<ul class="tags-picker">
|
||||||
|
{% for tag in alltags %}
|
||||||
|
<li>
|
||||||
|
<form action="/photo/{{ image.uuid }}/tag_add" method="post">
|
||||||
|
<input type="hidden" name="tag" value="{{ tag.uuid }}" />
|
||||||
|
<input class="submit-link" type="submit" value="{{ tag.title }}" />
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="add-tags pure-u-1-3">
|
||||||
|
<h2>Add tag</h2>
|
||||||
|
<form action="/photo/{{ image.uuid }}/tag_create" method="post" class="pure-form">
|
||||||
|
<input type="text" name="tag" placeholder="new tag name" />
|
||||||
|
<input type="submit" value="Add" class="pure-button pure-button-primary" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include "page-bottom.html" %}
|
Loading…
Reference in New Issue