mirror of
https://github.com/aquatix/digimarks.git
synced 2025-12-06 22:05:09 +01:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62fcf737d0 | |||
| 607a45ca8b | |||
| d5c6b751f9 | |||
| 50df87fb3e | |||
| 3f05bc36cc | |||
| ec9e7701da | |||
| 9ab2710114 | |||
| 8f1e70f51e | |||
| 7864cddd32 | |||
| 00c0e77c52 | |||
| 0111795e46 | |||
| 5fc780dac6 | |||
| 4bf7af08d5 | |||
| 6be78117c2 | |||
| 5f0e3bb730 | |||
| b230c5848d | |||
| 8bb8aff6c4 | |||
| 974fadf3d9 | |||
| 062b59dc50 | |||
| 6b7f7cfa16 | |||
| 4953f17364 | |||
| 798466f497 | |||
| 000d5be73e |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,9 +1,26 @@
|
||||
|
||||
## v0.2.0 (unreleased)
|
||||
## TODO
|
||||
|
||||
- Sorting of bookmarks
|
||||
- Sort by title
|
||||
- Sort by date
|
||||
- Logging of actions
|
||||
- json/rss views of public tag pages
|
||||
- On tags overview page:
|
||||
- Show which tags have public pages, with link
|
||||
- How many bookmarks each tag has
|
||||
|
||||
|
||||
## v0.2.0
|
||||
|
||||
2016-08-02
|
||||
|
||||
- Favicon courtesy Freepik on flaticon.com
|
||||
- Tag tags for easy adding of tags
|
||||
- Updates to MaterializeCSS and jQuery
|
||||
- Several bug- and code style fixes
|
||||
- Styling tweaks
|
||||
- Added 'Add bookmark' FAB to the bookmarks overview
|
||||
- Option to strip parameters from url (like '?utm_source=social')
|
||||
|
||||
|
||||
## v0.1.0
|
||||
|
||||
@@ -72,6 +72,12 @@ What's new?
|
||||
See the `Changelog`_.
|
||||
|
||||
|
||||
Attributions
|
||||
------------
|
||||
|
||||
'M' favicon by `Freepik`_.
|
||||
|
||||
|
||||
.. _digimarks: https://github.com/aquatix/digimarks
|
||||
.. _webhook: https://en.wikipedia.org/wiki/Webhook
|
||||
.. |PyPI version| image:: https://img.shields.io/pypi/v/digimarks.svg
|
||||
@@ -87,3 +93,4 @@ See the `Changelog`_.
|
||||
.. _vhost for Apache2.4: https://github.com/aquatix/digimarks/blob/master/example_config/apache_vhost.conf
|
||||
.. _uwsgi.ini: https://github.com/aquatix/digimarks/blob/master/example_config/uwsgi.ini
|
||||
.. _Changelog: https://github.com/aquatix/digimarks/blob/master/CHANGELOG.md
|
||||
.. _Freepik: http://www.flaticon.com/free-icon/letter-m_2041
|
||||
|
||||
57
digimarks.py
57
digimarks.py
@@ -1,3 +1,4 @@
|
||||
from __future__ import print_function
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
@@ -6,14 +7,14 @@ import requests
|
||||
import shutil
|
||||
import bs4
|
||||
from more_itertools import unique_everseen
|
||||
from urlparse import urlparse
|
||||
from urlparse import urlparse, urlunparse
|
||||
|
||||
from utilkit import datetimeutil
|
||||
|
||||
from flask import Flask, abort, redirect, render_template, request, url_for
|
||||
from flask_peewee.db import Database
|
||||
#from flask_peewee.utils import get_object_or_404
|
||||
from peewee import *
|
||||
from peewee import * # noqa
|
||||
|
||||
try:
|
||||
import settings
|
||||
@@ -155,6 +156,11 @@ class Bookmark(db.Model):
|
||||
tags_clean = clean_tags(tags_split)
|
||||
self.tags = ','.join(tags_clean)
|
||||
|
||||
@classmethod
|
||||
def strip_url_params(cls, url):
|
||||
parsed = urlparse(url)
|
||||
return urlunparse((parsed.scheme, parsed.netloc, parsed.path, parsed.params, '', parsed.fragment))
|
||||
|
||||
@property
|
||||
def tags_list(self):
|
||||
""" Get the tags as a list, iterable in template """
|
||||
@@ -196,9 +202,17 @@ def get_tags_for_user(userkey):
|
||||
return clean_tags(tags)
|
||||
|
||||
|
||||
def get_cached_tags(userkey):
|
||||
""" Fail-safe way to get the cached tags for `userkey` """
|
||||
try:
|
||||
return all_tags[userkey]
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return render_template('404.html'), 404
|
||||
return render_template('404.html', error=e), 404
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@@ -219,14 +233,16 @@ def bookmarks(userkey, sortmethod = None):
|
||||
#else:
|
||||
# abort(404)
|
||||
message = request.args.get('message')
|
||||
tags = get_cached_tags(userkey)
|
||||
|
||||
if request.method == 'POST':
|
||||
filter_on = request.form['filter']
|
||||
bookmarks = Bookmark.select().where(Bookmark.userkey == userkey, Bookmark.title.contains(filter_on),
|
||||
Bookmark.status == Bookmark.VISIBLE).order_by(Bookmark.created_date.desc())
|
||||
return render_template('bookmarks.html', bookmarks=bookmarks, userkey=userkey, tags=all_tags[userkey], filter=filter_on, message=message)
|
||||
return render_template('bookmarks.html', bookmarks=bookmarks, userkey=userkey, tags=tags, filter=filter_on, message=message)
|
||||
else:
|
||||
bookmarks = Bookmark.select().where(Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE).order_by(Bookmark.created_date.desc())
|
||||
return render_template('bookmarks.html', bookmarks=bookmarks, userkey=userkey, tags=all_tags[userkey], message=message)
|
||||
return render_template('bookmarks.html', bookmarks=bookmarks, userkey=userkey, tags=tags, message=message)
|
||||
|
||||
|
||||
|
||||
@@ -251,14 +267,17 @@ def editbookmark(userkey, urlhash):
|
||||
# bookmark = getbyurlhash()
|
||||
bookmark = Bookmark.get(Bookmark.url_hash == urlhash, Bookmark.userkey == userkey)
|
||||
message = request.args.get('message')
|
||||
return render_template('edit.html', action='Edit bookmark', userkey=userkey, bookmark=bookmark, message=message, formaction='edit')
|
||||
tags = get_cached_tags(userkey)
|
||||
return render_template('edit.html', action='Edit bookmark', userkey=userkey, bookmark=bookmark, message=message, formaction='edit', tags=tags)
|
||||
|
||||
|
||||
@app.route('/<userkey>/add')
|
||||
def addbookmark(userkey):
|
||||
""" Bookmark add form """
|
||||
bookmark = Bookmark(title='', url='', tags='')
|
||||
return render_template('edit.html', action='Add bookmark', userkey=userkey, bookmark=bookmark)
|
||||
message = request.args.get('message')
|
||||
tags = get_cached_tags(userkey)
|
||||
return render_template('edit.html', action='Add bookmark', userkey=userkey, bookmark=bookmark, tags=tags, message=message)
|
||||
|
||||
|
||||
def updatebookmark(userkey, request, urlhash = None):
|
||||
@@ -269,6 +288,9 @@ def updatebookmark(userkey, request, urlhash = None):
|
||||
starred = False
|
||||
if request.form.get('starred'):
|
||||
starred = True
|
||||
strip_params = False
|
||||
if request.form.get('strip'):
|
||||
strip_params = True
|
||||
|
||||
if url and not urlhash:
|
||||
# New bookmark
|
||||
@@ -278,11 +300,16 @@ def updatebookmark(userkey, request, urlhash = None):
|
||||
return redirect(url_for('editbookmark', userkey=userkey, urlhash=bookmark.url_hash, message=message))
|
||||
elif url:
|
||||
# Existing bookmark, get from DB
|
||||
bookmark = Bookmark.get(userkey == userkey, Bookmark.url_hash == urlhash)
|
||||
bookmark = Bookmark.get(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
||||
# Editing this bookmark, set modified_date to now
|
||||
bookmark.modified_date = datetime.datetime.now()
|
||||
else:
|
||||
# No url was supplied, abort. @TODO: raise exception?
|
||||
return None
|
||||
|
||||
bookmark.title = title
|
||||
if strip_params:
|
||||
url = Bookmark.strip_url_params(url)
|
||||
bookmark.url = url
|
||||
bookmark.starred = starred
|
||||
bookmark.set_tags(tags)
|
||||
@@ -305,14 +332,17 @@ def updatebookmark(userkey, request, urlhash = None):
|
||||
#@app.route('/<userkey>/adding')
|
||||
def addingbookmark(userkey):
|
||||
""" Add the bookmark from form submit by /add """
|
||||
tags = get_cached_tags(userkey)
|
||||
|
||||
if request.method == 'POST':
|
||||
bookmark = updatebookmark(userkey, request)
|
||||
if not bookmark:
|
||||
return redirect(url_for('addbookmark', userkey=userkey, message='No url provided', tags=tags))
|
||||
if type(bookmark).__name__ == 'Response':
|
||||
return bookmark
|
||||
all_tags[userkey] = get_tags_for_user(userkey)
|
||||
return redirect(url_for('editbookmark', userkey=userkey, urlhash=bookmark.url_hash))
|
||||
return redirect(url_for('add'))
|
||||
return redirect(url_for('addbookmark', userkey=userkey, tags=tags))
|
||||
|
||||
|
||||
@app.route('/<userkey>/<urlhash>/editing', methods=['GET', 'POST'])
|
||||
@@ -323,7 +353,7 @@ def editingbookmark(userkey, urlhash):
|
||||
bookmark = updatebookmark(userkey, request, urlhash=urlhash)
|
||||
all_tags[userkey] = get_tags_for_user(userkey)
|
||||
return redirect(url_for('editbookmark', userkey=userkey, urlhash=bookmark.url_hash))
|
||||
return redirect(url_for('add'))
|
||||
return redirect(url_for('editbookmark', userkey=userkey, urlhash=urlhash))
|
||||
|
||||
|
||||
@app.route('/<userkey>/<urlhash>/delete', methods=['GET', 'POST'])
|
||||
@@ -341,8 +371,7 @@ def deletingbookmark(userkey, urlhash):
|
||||
@app.route('/<userkey>/tags')
|
||||
def tags(userkey):
|
||||
""" Overview of all tags used by user """
|
||||
tags = get_tags_for_user(userkey)
|
||||
print tags
|
||||
tags = get_cached_tags(userkey)
|
||||
return render_template('tags.html', tags=tags, userkey=userkey)
|
||||
|
||||
|
||||
@@ -420,10 +449,10 @@ User.create_table(True)
|
||||
PublicTag.create_table(True)
|
||||
|
||||
users = User.select()
|
||||
print 'Current user keys:'
|
||||
print('Current user keys:')
|
||||
for user in users:
|
||||
all_tags[user.key] = get_tags_for_user(user.key)
|
||||
print user.key
|
||||
print(user.key)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# run the application
|
||||
|
||||
2
setup.py
2
setup.py
@@ -26,7 +26,7 @@ setup(
|
||||
# third part for minor release
|
||||
# second when api changes
|
||||
# first when it becomes stable someday
|
||||
version='0.1.0',
|
||||
version='0.2.0',
|
||||
author='Michiel Scholten',
|
||||
author_email='michiel@diginaut.net',
|
||||
|
||||
|
||||
BIN
static/favicon.ico
Normal file
BIN
static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
@@ -5,6 +5,7 @@
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/>
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}"/>
|
||||
|
||||
<!-- Chrome, Firefox OS and Opera -->
|
||||
<meta name="theme-color" content="#2e7d32" />
|
||||
@@ -16,8 +17,9 @@
|
||||
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto+Mono&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/>
|
||||
<link href="{{ url_for('static', filename='css/digimarks.css') }}" type="text/css" rel="stylesheet" media="screen,projection"/>
|
||||
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
|
||||
</head>
|
||||
<body class="grey lighten-4">
|
||||
<nav class="green darken-3" role="navigation">
|
||||
@@ -53,8 +55,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='js/init.js') }}"></script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</div>
|
||||
|
||||
<div class="input-field col l2 m2 s4">
|
||||
<p class="left-align"><button class="btn btn-large waves-effect waves-light" type="submit" name="submit">Filter</button></p>
|
||||
<p class="left-align"><button class="btn waves-effect waves-light" type="submit" name="submit">Filter</button></p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -118,4 +118,10 @@
|
||||
</div>
|
||||
#}
|
||||
</div>
|
||||
|
||||
<div class="fixed-action-btn" style="bottom: 45px; right: 24px;">
|
||||
<a class="btn-floating btn-large red" href="{{ url_for('addbookmark', userkey=userkey) }}">
|
||||
<i class="large material-icons">add</i>
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -56,6 +56,29 @@
|
||||
<input placeholder="tags, divided by comma's" type="text" name="tags" id="tags" value="{{ bookmark.tags }}" class="validate" />
|
||||
<label for="tags">Tags</label>
|
||||
</div>
|
||||
</div>
|
||||
{% if tags %}
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
{% for tag in tags %}
|
||||
<div class="chip" id="tag_{{ tag }}">
|
||||
{{ tag }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% for tag in tags %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#tag_{{ tag }}').on('click', function () {
|
||||
var text = $('#tags');
|
||||
text.val(text.val() + ', {{ tag }}');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
|
||||
<div class="input-field col s12">
|
||||
{#<i class="material-icons prefix">star</i>#}
|
||||
@@ -65,7 +88,7 @@
|
||||
|
||||
<div class="input-field col s12">
|
||||
<input type="checkbox" name="strip" id="strip" />
|
||||
<label for="strip">Strip parameters from url</label>
|
||||
<label for="strip">Strip parameters from url (like <em>?utm_source=social</em> - can break the link!)</label>
|
||||
</div>
|
||||
|
||||
{% if bookmark.url_hash %}
|
||||
@@ -96,13 +119,13 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="input-field col l2 m3 s4">
|
||||
<p class="left-align"><button class="btn btn-large waves-effect waves-light" type="submit" name="submit">Save <i class="material-icons right">send</i></button></p>
|
||||
<p class="left-align"><button class="btn waves-effect waves-light" type="submit" name="submit">Save <i class="material-icons right">send</i></button></p>
|
||||
</div>
|
||||
</form>
|
||||
{% if bookmark.url_hash %}
|
||||
<div class="input-field col l2 m3 s4">
|
||||
<form action="{{ url_for('deletingbookmark', userkey=userkey, urlhash=bookmark.url_hash) }}" method="POST">
|
||||
<p class="left-align"><button class="btn btn-large waves-effect waves-light" type="submit" name="delete">Delete <i class="material-icons right">delete</i></button></p>
|
||||
<p class="left-align"><button class="btn waves-effect waves-light" type="submit" name="delete">Delete <i class="material-icons right">delete</i></button></p>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user