No description
Find a file
2018-05-01 21:03:10 -07:00
etiquette Fix handling of the event that a file loses its thumbnail. 2018-05-01 20:41:38 -07:00
frontends Don't use shortlink for zoom url. It breaks caching. 2018-05-01 21:03:10 -07:00
tests Create new files for tests. Though still empty. 2018-02-16 21:45:36 -08:00
utilities/database_upgrader Rename config user.min_length -> min_username_length. 2018-04-15 14:36:07 -07:00
.gitignore checkpoint 2016-09-18 01:33:46 -07:00
CONTRIBUTING.md Add some contact info to contributing.md. 2018-03-19 04:03:45 -07:00
LICENSE.txt Apply BSD 2-Clause License 2017-03-17 02:48:11 -07:00
README.md Update to do list with more batching ideas. 2018-05-01 18:06:27 -07:00
requirements.txt Bump voussoirkit requirement to 0.0.23 for cacheclass.__contains__. 2018-03-18 21:00:58 -07:00

Etiquette

I am currently running a demonstration copy of Etiquette at http://etiquette.voussoir.net where you can browse around. This is not yet permanent.

What am I looking at

Etiquette is a tag-based file organization system with a web front-end.

Setting up

I have not made a setup.py yet. So you must make the etiquette package importable in one of two ways:

  • By editing your PYTHONPATH environment variable. Note that the path refers to the Etiquette repository location and not the etiquette package folder:

    Windows: set "PYTHONPATH=%PYTHONPATH%;D:\Git\Etiquette" Note the semicolon to delimit paths. To make permanent, use the Environment Variable editor or the setx command. The editor is better.

    Linux: PYTHONPATH="$PYTHONPATH:/home/Owner/Git/Etiquette" Note the colon to delimit paths. To make permanent, add the export to your bashrc.

  • By placing it in one of your lib paths, or using filesystem junctions to make it appear in a lib path. Note that this time, the path does refer to the package itself.

    The easiest way to find your lib path is python -c "import os; print(os)".

    Windows: mklink /J fakepath realpath
    for example mklink /J "C:\Python36\Lib\etiquette" "D:\Git\Etiquette\etiquette"

    Linux: ln --symbolic realpath fakepath
    for example ln --symbolic "/home/Owner/Git/Etiquette/etiquette" "/usr/local/lib/python3.6/etiquette"

I'm sure you'll figure it out.

Running locally

  • Run python etiquette_flask_launch.py [port] to launch the flask server. Port defaults to 5000 if not provided.

  • Run python -i etiquette_repl_launch.py to launch the Python interpreter with the PhotoDB pre-loaded into a variable called P. Try things like P.new_photo or P.digest_directory.

  • Note: Do not cd into the frontends folder. Stay wherever you want the photodb to be created, and start the frontend by specifying full file path of the launch file.

      D:\somewhere>python D:\Git\Etiquette\frontends\etiquette_flask\etiquette_flask_launch.py 5001
      /home/Owner>python /home/Owner/Git/Etiquette/frontends/etiquette_flask/etiquette_flask_launch.py 5001
    

Running with Gunicorn

  1. Use the PYTHONPATH technique to make etiquette and etiquette_flask both importable. Symlinking into the lib is not as convenient here because the server relies on the static files and jinja templates relative to the code's location.

     PYTHONPATH="$PYTHONPATH:/home/Owner/Git/Etiquette:/home/Owner/Git/Etiquette/frontends/etiquette_flask
    
  2. To run non-daemonized, on a specific port, with logging to the terminal, use:

     gunicorn etiquette_flask_entrypoint:site --bind "0.0.0.0:PORT" --access-logfile "-"
    

Project stability

You may notice that Etiquette doesn't have a version number anywhere. That's because I don't think it's ready for one. I am using this project to learn and practice, and breaking changes are very common.

Project structure

Here is a brief overview of the project to help you learn your way around:

  • etiquette
    The core backend package.
    • objects
      Definition of the Etiquette data objects like Photos and Tags.
    • photodb
      Definition of the PhotoDB class and its Mixins.
  • frontends
    Ideally, the backend should be frontend-agnostic. Even though the Flask interface is my primary interest, it should not feel like it must be the only one. Therefore I place it in this folder to indicate that other frontends are possible too. Every folder here is essentially a completely separate project.
    • etiquette_flask
      This folder represents the flask server as somewhat of a black box, in the sense that you can move it around and just run the contained launch file. Subfolders contain the HTML templates, static files, and site code.
      • etiquette_flask
        The package that contains the site's actual API code.
    • etiquette_repl
      Preloads a few variables into the interpreter so you can quickly test functions within the Python REPL itself.
  • utilities
    For other scripts that will be used with etiquette databases, but are not part of the library itself.

To do list

  • Make the wording between "new", "create", "add"; and "remove", "delete" more consistent.
  • User account system, permission levels, private pages.
  • Improve the "tags on this page" list. Maybe add separate buttons for must/may/forbid on each.
  • Some way for the database to re-identify a file that was moved / renamed (lost & found). Maybe file hash of the first few mb is good enough.
  • Debate whether the UserMixin.login method should accept usernames or I should standardize the usage of IDs only internally.
  • Ability to access user photos by user's ID, not just username.
  • Replace columns like area, ratio, bitrate by using expression indices or views (width * height etc).
  • Add a Photo.merge to combine duplicate entries.
  • Generate thumbnails for vector files without falling victim to bombs.
  • Allow photos to have nonstandard, orderby-able properties like "release year". How?
  • Currently, the Jinja templates are having a tangling influence on the backend objects, because Jinja cannot import my other modules like bytestring, but it can access the methods of the objects I pass into the template. As a result, the objects have excess helper methods. Consider making them into Jinja filters instead. Which is also kind of ugly but will move that pollution out of the backend at least.
  • Perhaps instead of actually deleting objects, they should just have a deleted flag, to make easy restoration possible. Also consider regrouping the children of restored Groupables if those children haven't already been reassigned somewhere else.
  • Add a new table to store permanent history of add/remove of tags on photos, so that accidents or trolling can be reversed.
  • Fix album size cache when photo reload metadata and generally improve that validation.
  • Better bookmark url validation.
  • Create a textbox which gives autocomplete tag names.
  • Consider if the "did you commit too early" warning should actually be an exception.
  • Extension currently does not believe in the override filename. On one hand this is kind of good because if they override the name to have no extension, we can still provide a downloadable file with the correct extension by remembering it. But on the other hand it does break the illusion of override_filename.
  • When batch fetching objects, consider whether or not a NoSuch should be raised. Perhaps a warningbag should be used.
  • Find a way to batch the fetching of photo tags in a way that isn't super ugly (e.g. on an album page, the photos themselves are batched, but then the photo.get_tags() on each one is not. In order to batch this we would have to have a separate function that fetches a whole bunch of tags and assigns them to the photo object).
  • Consider using executemany for some of the batch operations.

To do list: User permissions

Here are some thoughts about the kinds of features that need to exist within the permission system. I don't know how I'll actually manage it just yet. Possibly a permissions table in the database with user_id | permission where permission is some reliably-formatted string.

  • Preventing logged out users from viewing any page except root and /login.
  • Uploading photos (can_upload)
    • File extension restrictions
  • Add / remove tags from photo
    • My own photos (can_tag_own)
    • Explicit individual allow / deny (can_tag_photo:<photo_id>)
    • General allow / deny (can_tag)
  • Deleting photos
    • etc
  • Creating albums
    • As children of my own albums
  • Add / remove photos from album, edit title / desc.
    • My own albums (can_edit_album_own)
    • Explicit (can_edit_album:<album_id>)
    • General (can_edit_album)
  • Deleting albums
    • etc
  • Creating tags (can_create_tag)
  • Deleting tags (can_delete_tag)
    • Only those that I have created (can_delete_tag_own)
    • Any time vs. only if they are not in use (can_delete_tag_in_use)

Changelog

  • [addition] A new feature was added.
  • [bugfix] Incorrect behavior was fixed.
  • [change] An existing feature was slightly modified or parameters were renamed.
  • [cleanup] Code was improved, comments were added, or other changes with minor impact on the interface.
  • [removal] An old feature was removed.