Compare commits
No commits in common. "c036ec2797f044ad0efb4c5d38cb7559bb12be94" and "e04705e16128714ed0b3fd01b2320850183c17cd" have entirely different histories.
c036ec2797
...
e04705e161
|
@ -1,5 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import ZODB
|
||||
import ZODB.FileStorage
|
||||
storage = ZODB.FileStorage.FileStorage("pupper.db")
|
||||
db = ZODB.DB(storage)
|
||||
print(db.open().root())
|
||||
|
||||
def main():
|
||||
storage = ZODB.FileStorage.FileStorage("pupper.db")
|
||||
db = ZODB.DB(storage)
|
||||
for k, v in db.open().root.nodes.items():
|
||||
print(k, v.name, ":", v, "\n\t", v.body, "\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import cherrypy
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from nodepupper.nodeops import NodeOps, NObject
|
||||
from nodepupper.nodeops import NodeOps, NObject, NClass, NClassAttachment
|
||||
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||
from nodepupper.common import pwhash
|
||||
import math
|
||||
|
@ -43,6 +43,7 @@ class AppWeb(object):
|
|||
self.tpl.filters.update(basename=os.path.basename,
|
||||
ceil=math.ceil,
|
||||
statusstr=lambda x: str(x).split(".")[-1])
|
||||
self.node = NodesWeb(self)
|
||||
|
||||
def render(self, template, **kwargs):
|
||||
"""
|
||||
|
@ -70,7 +71,7 @@ class AppWeb(object):
|
|||
"all_tags": [], #tagq,
|
||||
"all_albums": [], #albumq,
|
||||
"path": cherrypy.request.path_info,
|
||||
"auth": auth()
|
||||
"auth": True or auth()
|
||||
}
|
||||
#s.close()
|
||||
return ret
|
||||
|
@ -80,111 +81,20 @@ class AppWeb(object):
|
|||
print(op, body, fqdn)
|
||||
if op in ("Edit", "Create") and body and fqdn:
|
||||
with self.nodes.db.transaction() as c:
|
||||
c.root.nodes[fqdn] = NObject(body)
|
||||
|
||||
obj = c.root.nodes[fqdn] if fqdn in c.root.nodes else NObject(fqdn, body)
|
||||
obj.body = body
|
||||
c.root.nodes[fqdn] = obj
|
||||
with self.nodes.db.transaction() as c:
|
||||
yield self.render("node_edit.html", node_name=node, node=c.root.nodes.get(node, None))
|
||||
yield self.render("node_edit.html", node=c.root.nodes.get(node, None))
|
||||
|
||||
@cherrypy.expose
|
||||
def index(self):
|
||||
"""
|
||||
"""
|
||||
with self.nodes.db.transaction() as c:
|
||||
yield self.render("nodes.html", nodes=c.root.nodes.items())
|
||||
yield self.render("nodes.html", nodes=c.root.nodes.values())
|
||||
# raise cherrypy.HTTPRedirect('feed', 302)
|
||||
|
||||
@cherrypy.expose
|
||||
def feed(self, page=0, pgsize=25):
|
||||
"""
|
||||
/feed - main photo feed - show photos sorted by date, newest first
|
||||
"""
|
||||
s = self.session()
|
||||
page, pgsize = int(page), int(pgsize)
|
||||
total_sets = photo_auth_filter(s.query(func.count(PhotoSet.id))).first()[0]
|
||||
images = photo_auth_filter(s.query(PhotoSet)).order_by(PhotoSet.date.desc()). \
|
||||
offset(pgsize * page).limit(pgsize).all()
|
||||
yield self.render("feed.html", images=[i for i in images], page=page, pgsize=int(pgsize), total_sets=total_sets)
|
||||
|
||||
@cherrypy.expose
|
||||
def stats(self):
|
||||
"""
|
||||
/stats - show server statistics
|
||||
"""
|
||||
s = self.session()
|
||||
images = photo_auth_filter(s.query(func.count(PhotoSet.uuid),
|
||||
func.strftime('%Y', PhotoSet.date).label('year'),
|
||||
func.strftime('%m', PhotoSet.date).label('month'))). \
|
||||
group_by('year', 'month').order_by(desc('year'), desc('month')).all()
|
||||
tsize = photo_auth_filter(s.query(func.sum(Photo.size)).join(PhotoSet)).scalar() # pragma: manual auth
|
||||
yield self.render("monthly.html", images=images, tsize=tsize)
|
||||
|
||||
@cherrypy.expose
|
||||
def map(self, i=None, a=None, zoom=3):
|
||||
"""
|
||||
/map - show all photos on the a map. Passing $i will show a single photo, or passing $a will show photos under
|
||||
the given tag.
|
||||
TODO using so many coordinates is slow in the browser. dedupe them somehow.
|
||||
"""
|
||||
s = self.session()
|
||||
query = photo_auth_filter(s.query(PhotoSet)).filter(PhotoSet.lat != 0, PhotoSet.lon != 0)
|
||||
if a:
|
||||
query = query.join(TagItem).join(Tag).filter(Tag.uuid == a)
|
||||
if i:
|
||||
query = query.filter(PhotoSet.uuid == i)
|
||||
yield self.render("map.html", images=query.all(), zoom=int(zoom))
|
||||
|
||||
@cherrypy.expose
|
||||
@require_auth
|
||||
def create_tags(self, fromdate=None, uuid=None, tag=None, newtag=None, remove=None):
|
||||
"""
|
||||
/create_tags - tag multiple items selected by day of photo
|
||||
:param fromdate: act upon photos taken on this day
|
||||
:param uuid: act upon a single photo with this uuid
|
||||
:param tag: target photos will have a tag specified by this uuid added
|
||||
:param remove: target photos will have the tag specified by this uuid removed
|
||||
:param newtag: new tag name to create
|
||||
"""
|
||||
s = self.session()
|
||||
|
||||
def get_photos():
|
||||
if fromdate:
|
||||
dt = datetime.strptime(fromdate, "%Y-%m-%d")
|
||||
dt_end = dt + timedelta(days=1)
|
||||
photos = s.query(PhotoSet).filter(and_(PhotoSet.date >= dt,
|
||||
PhotoSet.date < dt_end)).order_by(PhotoSet.date)
|
||||
num_photos = s.query(func.count(PhotoSet.id)). \
|
||||
filter(and_(PhotoSet.date >= dt, PhotoSet.date < dt_end)).order_by(PhotoSet.date).scalar()
|
||||
|
||||
if uuid:
|
||||
photos = s.query(PhotoSet).filter(PhotoSet.uuid == uuid)
|
||||
num_photos = s.query(func.count(PhotoSet.id)).filter(PhotoSet.uuid == uuid).scalar()
|
||||
return photos, num_photos
|
||||
|
||||
if remove:
|
||||
rmtag = s.query(Tag).filter(Tag.uuid == remove).first()
|
||||
photoq, _ = get_photos()
|
||||
for photo in photoq:
|
||||
s.query(TagItem).filter(TagItem.tag_id == rmtag.id, TagItem.set_id == photo.id).delete()
|
||||
s.commit()
|
||||
|
||||
if newtag:
|
||||
s.add(Tag(title=newtag.capitalize(), name=newtag, slug=slugify(newtag)))
|
||||
s.commit()
|
||||
|
||||
photos, num_photos = get_photos()
|
||||
|
||||
if tag: # Create the tag on all the photos
|
||||
tag = s.query(Tag).filter(Tag.uuid == tag).first()
|
||||
for photo in photos.all():
|
||||
if 0 == s.query(func.count(TagItem.id)).filter(TagItem.tag_id == tag.id,
|
||||
TagItem.set_id == photo.id).scalar():
|
||||
s.add(TagItem(tag_id=tag.id, set_id=photo.id))
|
||||
s.commit()
|
||||
|
||||
alltags = s.query(Tag).order_by(Tag.name).all()
|
||||
yield self.render("create_tags.html", images=photos, alltags=alltags,
|
||||
num_photos=num_photos, fromdate=fromdate, uuid=uuid)
|
||||
|
||||
@cherrypy.expose
|
||||
def login(self):
|
||||
"""
|
||||
|
@ -210,6 +120,19 @@ class AppWeb(object):
|
|||
yield self.render("error.html", status=status, message=message, traceback=traceback)
|
||||
|
||||
|
||||
@cherrypy.popargs("node")
|
||||
class NodesWeb(object):
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.nodes = root.nodes
|
||||
self.render = root.render
|
||||
|
||||
@cherrypy.expose
|
||||
def index(self, node):
|
||||
with self.nodes.db.transaction() as c:
|
||||
yield self.render("node.html", node=c.root.nodes[node])
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
import signal
|
||||
|
|
|
@ -5,14 +5,30 @@ import persistent.list
|
|||
import BTrees.OOBTree
|
||||
|
||||
|
||||
def plist():
|
||||
return persistent.list.PersistentList()
|
||||
|
||||
|
||||
class NObject(persistent.Persistent):
|
||||
|
||||
def __init__(self, body=None):
|
||||
self.parents = persistent.list.PersistentList()
|
||||
def __init__(self, fqdn, body):
|
||||
self.fqdn = fqdn
|
||||
self.parents = plist()
|
||||
self.classes = plist()
|
||||
self.body = body
|
||||
|
||||
# def add_author(self, author):
|
||||
# self.authors.append(author)
|
||||
|
||||
class NClass(persistent.Persistent):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
class NClassAttachment(persistent.Persistent):
|
||||
|
||||
def __init__(self, cls, conf):
|
||||
self.cls = persistent.list.PersistentList()
|
||||
self.conf = conf
|
||||
|
||||
|
||||
class NodeOps(object):
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
{% extends "page.html" %}
|
||||
{% block title %}{{ node.fqdn }}{% endblock %}
|
||||
{% block subtitle %}placehoolder{% endblock %}
|
||||
|
||||
{% block buttons %}
|
||||
<form action="/tag/{{ tag.uuid }}/op" method="post">
|
||||
{% if tag.is_album %}<input type="submit" class="secondary-button pure-button" name="op" value="Demote to tag" />{% else %}
|
||||
<input type="submit" class="secondary-button pure-button" name="op" value="Promote to album" />{% endif %}
|
||||
<input type="submit" class="secondary-button pure-button" name="op" value="Make all public" />
|
||||
<input type="submit" class="secondary-button pure-button" name="op" value="Make all private" />
|
||||
<input type="submit" class="secondary-button pure-button" name="op" value="Delete tag" />
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="nodes-single">
|
||||
<div class="node">
|
||||
<h2>{{ node.name }}</h2>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<pre>
|
||||
{{ node.body }}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "page.html" %}
|
||||
{% block title %}{% if node %}Edit{% else %}Create{% endif %} node{% endblock %}
|
||||
{% block subtitle %}{% if node %}Editing "{{ node_name }}"{% else %}New item{% endif %}{% endblock %}
|
||||
{% block subtitle %}{% if node %}Editing "{{ node.fqdn }}"{% else %}New item{% endif %}{% endblock %}
|
||||
|
||||
{% block buttons %}
|
||||
{% if node is defined %}<a href="/nodes/{{ image.uuid }}"><button class="secondary-button pure-button">Back</button></a>{% endif %}
|
||||
|
@ -13,7 +13,7 @@
|
|||
<form action="/node_edit" method="post" class="pure-form pure-form-stacked">
|
||||
<fieldset>
|
||||
<fieldset class="pure-group pure-u-1">
|
||||
<input name="fqdn" type="text" class="pure-input-1" placeholder="FQDN" value="{{ node_name or '' }}" />
|
||||
<input name="fqdn" type="text" class="pure-input-1" placeholder="FQDN" value="{{ node.fqdn or '' }}" />
|
||||
<textarea name="body" class="pure-input-1" placeholder="Body" rows="15">{{ node and node.body or '' }}</textarea>
|
||||
</fieldset>
|
||||
<!-- <div class="pure-u-1">
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
{% block body %}
|
||||
|
||||
<div class="nodes-all">
|
||||
{% for name, node in nodes %}
|
||||
{% for node in nodes %}
|
||||
<div class="node">
|
||||
<h2>{{ name }}</h2>
|
||||
<h2>{{ node.fqdn }}</h2>
|
||||
<p>
|
||||
<a href="/node_edit?node={{ name }}">edit</a>
|
||||
<a href="/node/{{ node.fqdn }}">view</a> <a href="/node_edit?node={{ node.fqdn }}">edit</a>
|
||||
</p>
|
||||
<pre>
|
||||
{{ node.body }}
|
||||
|
|
Loading…
Reference in New Issue