Compare commits

...

No commits in common. "c036ec2797f044ad0efb4c5d38cb7559bb12be94" and "e04705e16128714ed0b3fd01b2320850183c17cd" have entirely different histories.

6 changed files with 86 additions and 110 deletions

14
checkdb.py Normal file → Executable file
View File

@ -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()

View File

@ -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

View File

@ -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):

29
templates/node.html Normal file
View File

@ -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 %}

View File

@ -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">

View File

@ -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 }}