Git Product home page Git Product logo

webtodotxt's Introduction

Web Todo.txt

A web-based GUI to manage a Todo.txt file.

Features

  • Add / edit / remove tasks
  • Tasks due date (WIP)
  • Filters on all possible task data
  • Projects and contexts are cached locally for future use (using localStorage) (WIP)
  • Automatic sorting
  • Save and reload the task list
  • Clear displaying of the task priority and completion
  • Automatic task creation date and completion date setting
  • Links are automatically created for URLs and email addresses
  • Possible to integrate with other system using a very basic "API" (I put API in quotes because it isn't really an API). See below for more information
  • Warns before quitting if your task list wasn't saved to prevent data loss
  • Support 2 storage backends (see below in the Supported storage backends section for the list)
  • Internationalized & localized in 3 languages:
    • English (en)
    • French (fr)
    • Portuguese (WIP) (pt)
    • German (de)
  • Multi authentication backend support

Prerequisites

  • Should work on any Python 3.x version. Feel free to test with another Python version and give me feedback
  • A uWSGI-capable web server (optional, but recommended)
  • A modern web browser (which optionally support localStorage)

Installation

  1. Clone this repo somewhere
  2. pip install -r requirements.txt
  3. pybabel compile -d translations
  4. IMPORTANT: Other dependencies are needed regarding the storage backend you'll use. Please refer to the table in the Supported storage backends section below and install them accordingly using pip install <package> before continuing

Configuration

Copy the config.example.py file to config.py and fill in the configuration parameters.

Available configuration parameters are:

  • SECRET_KEY Set this to a complex random value

More informations about Flask config values can be found here.

  • TITLE If set to a string, will be used to replace the default app title (which is "Web Todo.txt")
  • USERS The credentials required to access the app. You can specify multiple ones. It is highly recommended to serve Web Todo.txt through HTTPS because it uses HTTP basic auth
  • FORCE_LANGUAGE Force the lang to be one of the supported ones (defaults to None: auto-detection from the Accept-Language HTTP header). See in the features section above for a list of available lang keys
  • DEFAULT_LANGUAGE Default language if it cannot be determined automatically. Not taken into account if FORCE_LANGUAGE is defined. See in the features section above for a list of available lang keys
  • DISPLAY_CREATION_DATE Whether the creation date of the tasks must be displayed or not
  • STORAGE_BACKEND_TO_USE The storage backend to use. Can be one of the ones in the table below, in the Supported storage backends section
  • STORAGE_BACKENDS Self-explanatory storage backends-specific configuration values. Don't forget to change them before using your desired storage backend
  • AUTH_BACKEND_TO_USE Let you select one of the available auth backends. See Supported auth backends section.

I'll let you search yourself about how to configure a web server along uWSGI.

Usage

  • Standalone

Run the internal web server, which will be accessible at http://localhost:8080:

python local.py

Edit this file and change the interface/port as needed.

  • uWSGI

The uWSGI file you'll have to set in your uWSGI configuration is uwsgi.py. The callable is app.

  • Docker

Build the image in the applications root dir:

docker build -t <image_name> .

The image can be configured via environment variables. The available variables are:

Variable Default Description
SECRET_KEY this-is-not-a-secret-key! The secret key of the app. PLEASE CHANGE THIS!
USER_DICT {} The set of predefined users as python-sict (e.g. {"john": "secret_pass"}
AUTH_BACKEND DictAuth The authentication backend to use.
STORAGE_BACKEND FileSystem The storage backend to use.
TODO_FILE_PATH Backend-dependend The path to the todo.txt in all backends
DROPBOX_ACCESS_TOKEN None The accesstoken that is used if storage backend is dropbox
WEBDAV_HOST https://my.webdav.com The hostname of the webdav server if WebDav storage is used.
MODE http The mode the uwsgi should operate in. If set to http it can be used as a normal webserver. The other option is socket which enables the uwsgi protocol.

Please mention @janLO in issues with the docker support.

  • Others

You'll probably have to hack with this application to make it work with one of the solutions described here. Send me a pull request if you make it work.

How it works

This project is built on Vue.js 2 for the frontend and Flask (Python) for the backend. The todotxtio PyPI package is used to parse/write the Todo.txt file, giving/receiving data through Ajax. Several storage backends are available so one can choose to save its Todo.txt file locally on the filesystem, on its Dropbox or in a WebDav instance like Nextcloud.

"API"

Please navigate here for the full docs.

Gotchas

  • Be aware that this web application isn't intended to be used on mobile devices

Instead, use native mobile apps to edit and sync the Todo.txt file:

On Android, you can use Simpletask (free) which can natively sync your tasks with your Dropbox and Nextcloud. If you're using another storage provider (third-party or self-hosted), you can use a modified version of this app called Simpletask Cloudless (also free, from the same author) which comes with no sync at all, but instead saves all your tasks in a file on your device. You can then do whatever you want with this file like syncing it via SFTP or many other providers / protocols with FolderSync (free, but a pro version is available).

On iOS, I don't know. Feel free to share your finds.

  • This web application wasn't designed to be multi-process compliant

If you sync your Todo.txt file via Dropbox or something from the mobile apps and at the same time you're modifiying it via this web app, you'll probably end with a loss of data because both sides can't be aware of the latest version of the file in realtime: they both erase the file with their data.

So make sure you're modifying it from one location at a time with the latest up-to-date Todo.txt file.

Supported auth backends

Name Configuration value Additional PyPI dependencies
Predefined users DictAuth
WebDAV auth WebDavAuth webdavclient3

The DictAuth uses the USERS dict from the config as user database. With this nothing fancy happens at all. The WebDavAuth has no local user database. It forwards the login data from the user to the configured webdav server and tries to log in on his behalf. If this is successful, access will be granted.

Supported storage backends

Name Configuration value Additional PyPI dependencies
Local file system FileSystem
Dropbox Dropbox dropbox
WebDAV WebDav webdavclient3

Multi user support

The WebDav storage backend has two special features:

  • The path of the todo.txt file can contain a placeholder for the user in the form {username} which will be replaced by the current user name. With this its possible to have multiple todo files for multiple users.
  • The actual credentials of the user will be either taken from the backends config values webdav_login and webdav_password or, if omitted, from the current user.

With these features there are several multi-user-scenarios possible:

  • You can have predefined users in the USERS dict that share one and the same todo file (no user placeholder, dav credentials given in the storage config and DictAuth).
  • You can have predefined users in the USERS dict which each has its own todo.txt file on the same storage (filename with user placeholder, dav credentials given in the storage config and DictAuth)
  • You can have all the above using your webdav server as an auth backend by using the WebDavAuth.
  • You can have each webdav user have its own file on its own storage by using the placeholder and omitting the dav credentials from the storage config.

Nextcloud Usage

To use a nextcloud storage you have to specify the whole file path (from the host part on) as path. If your server is named my.nextcloud.home then the storage config should look like this:

    'WebDav': {
        'path': 'remote.php/dav/files/<username>/todo.txt',
        'webdav_hostname': 'https://my.nextcloud.home',
        'webdav_login': '<username>',
        'webdav_password': '<PASSWORD>'
    }

Username and password are your regular nextcloud credentials. I highly recommend to not store them in the config. Instead use the WebDavAuth method:

AUTH_BACKEND_TO_USE = 'WebDavAuth'
[...]
    'WebDav': {
        'path': 'remote.php/dav/files/<username>/todo.txt',
        'webdav_hostname': 'https://my.nextcloud.home',
    }

If you want no user specific configuration in your config you can use the placeholder method:

AUTH_BACKEND_TO_USE = 'WebDavAuth'
[...]
    'WebDav': {
        'path': 'remote.php/dav/files/{username}/todo.txt',
        'webdav_hostname': 'https://my.nextcloud.home',
    }

Contributors

Thanks to:

  • @Pepsit36 (Portuguese translations)
  • @janLo (WebDav auth & storage support, Dockerfile)
  • @Strubbl (German translation)

End words

If you have questions or problems, you can submit an issue.

You can also submit pull requests. It's open-source man!

webtodotxt's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webtodotxt's Issues

Multi-edit

Edit several task data at the same time:

  • Completed
  • Projects
  • Contexts
  • Due date
  • Priority

Support a tag like h:1 for hiding items from the list

It would be nice to have this web app support hidden tasks. This is already supported by the Simpletasks Android application and well explained in their documentation:

Hidden tasks with h:1, this allows dummy tasks with predefined lists and tags so that lists and tags will be available even if the last task with the tag/list is removed from todo.txt. These tasks will not be shown by default. You can temporarily display them from the Settings.

https://github.com/mpcjanssen/simpletask-android/blob/master/app/src/main/assets/index.en.md#extensions

It would be nice if the webtodotxt application would support the same hidden tag as Simpletasks and automatically hide hidden tasks. Furthermore the filter menu should have the possibility to switch between showing hidden tasks and not showing them. Default option shall be to hide tasks with that special tag.

Save filters locally

Using LocalStorage. This way, when opening Web Todo.txt, filters are restored automagically.

Logging in

Hi, after submitting correct user & password I get the error:

A server error occured! Please retry. If the error persists, please report an issue here.

in the console the following:

192.168.0.23 - - [08/Sep/2018 12:43:12] "GET / HTTP/1.1" 401 -
[2018-09-08 12:43:18,034] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python2.7/dist-packages/flask_httpauth.py", line 97, in decorated
    password = self.get_auth_password(auth)
  File "/usr/local/lib/python2.7/dist-packages/flask_httpauth.py", line 83, in get_auth_password
    password = self.get_password_callback(auth.username)
  File "/opt/webtodotxt/hooks.py", line 19, in get_password
    backend = get_current_auth_backend()
  File "/opt/webtodotxt/helpers.py", line 31, in get_current_auth_backend
    return getattr(auth_backends, name)()
  File "/opt/webtodotxt/auth_backends.py", line 24, in __init__
    super(DictAuth, self).__init__(*args, **kwargs)
TypeError: super() argument 1 must be type, not classobj

webdav Read timed out

Today, i rebuilt the docker container with all updated components (alpine updates, python dependency updates etc) and it stopped working. I always get a connection timeout error.

I am using WebdavAuth. It worked until today before i updated.

The only python requirement which got recently updated is https://pypi.org/project/Flask-HTTPAuth/#history
But maybe some python core dependency got updated too?

With two other clients, the webdav (with nextcloud) works fine. Even Simpletask app with Nextcloud support still works fine.

Do you have any idea how i can recover from this error?

My error message is:

[2018-06-06 20:41:01,478] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 387, in _make_request
    six.raise_from(e, None)
  File "<string>", line 2, in raise_from
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 383, in _make_request
    httplib_response = conn.getresponse()
  File "/usr/local/lib/python3.6/http/client.py", line 1331, in getresponse
    response.begin()
  File "/usr/local/lib/python3.6/http/client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "/usr/local/lib/python3.6/http/client.py", line 258, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/local/lib/python3.6/socket.py", line 586, in readinto
    return self._sock.recv_into(b)
  File "/usr/local/lib/python3.6/ssl.py", line 1009, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/local/lib/python3.6/ssl.py", line 871, in read
    return self._sslobj.read(len, buffer)
  File "/usr/local/lib/python3.6/ssl.py", line 631, in read
    v = self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 440, in send
    timeout=timeout
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 639, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/usr/local/lib/python3.6/site-packages/urllib3/util/retry.py", line 357, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "/usr/local/lib/python3.6/site-packages/urllib3/packages/six.py", line 686, in reraise
    raise value
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 601, in urlopen
    chunked=chunked)
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 389, in _make_request
    self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 309, in _raise_timeout
    raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value)
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='cloud.test.de', port=443): Read timed out. (read timeout=30)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/webdav3/client.py", line 70, in _wrapper
    res = fn(self, *args, **kw)
  File "/usr/local/lib/python3.6/site-packages/webdav3/client.py", line 273, in check
    response = self.execute_request(action='check', path=urn.quote())
  File "/usr/local/lib/python3.6/site-packages/webdav3/client.py", line 164, in execute_request
    data=data
  File "/usr/local/lib/python3.6/site-packages/requests/api.py", line 58, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 508, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 618, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 521, in send
    raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='cloud.test.de', port=443): Read timed out. (read timeout=30)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.6/site-packages/flask_httpauth.py", line 85, in decorated
    password = self.get_password_callback(auth.username)
  File "./hooks.py", line 21, in get_password
    return backend.retrieve_password(username)
  File "./auth_backends.py", line 49, in retrieve_password
    if client.check(self.config['path'].format(username=username)):
  File "/usr/local/lib/python3.6/site-packages/webdav3/client.py", line 74, in _wrapper
    raise ConnectionException(re)
webdav3.exceptions.ConnectionException: HTTPSConnectionPool(host='cloud.test.de', port=443): Read timed out. (read timeout=30)
[pid: 15|app: 0|req: 6/8] 172.17.0.1 () {48 vars in 998 bytes} [Wed Jun  6 20:40:31 2018] GET / => generated 1594 bytes in 30114 msecs (HTTP/1.0 500) 2 headers in 100 bytes (1 switches on core 1)
[pid: 16|app: 0|req: 3/9] 172.17.0.1 () {48 vars in 1019 bytes} [Wed Jun  6 20:41:01 2018] GET /todotxt-static/css/app.css => generated 8929 bytes in 2 msecs via sendfile() (HTTP/1.0 200) 8 headers in 301 bytes (0 switches on core 0)

Support of common metadata

Stored in the so called "tags" by todotxtio:

  • due:YYYY-MM-DD (due date)

    • Deleting
    • Setting
  • h:1 (hidden tasks)

    • Deleting
    • Setting

Save each project/context that was used

Each project/context must be persisted in the localStorage. If there's no more todo that are using them, they will still be available.

Also allow to remove them (but only if they are no more used).

  • Projects
    • Saving
    • Deleting
  • Contexts
    • Saving
    • Deleting
  • Improve localStorage support detection

NOTICE: this project is abandoned and is no longer maintained

Dear developers,

I regret to inform you this project is abandoned and is no longer maintained, it has thus been archived. I no longer have interest for the Todo.txt file format.

Feel free to create a fork, publish on PyPI or whatever you want as long as it's complying with the license.

Thanks to the past contributors.

Best regards,

Maxime

Editing a task's first chars leads to jumping it to another position in the list

The tasks are always sorted alphabetical by default. If i click on the edit button and change the first chars from a task, the tasks moves to another position on the list.
This gets worse if my list is longer than a full page and the task i am typing chars into is hidden now. Of course this is a minor bug, but it might improve the user experience for editing existing tasks a lot.

It would be nice, if the task, which i am currently editing, gets only resorted when i hit save.

Error: Access to this resource is forbidden.

Hi,

First off thank you for doing this. I really like todo.txt but I can't use it right now on my new work computer because I am not allowed to install software myself on it (including Chrome which would at least give me the extension). My only solution is finding a browser access. So thanks!

Anyway I found your git and am trying to spin it up. I am not a very experienced wed developer. So I apologize in advance if my questions are a bit naive. For your information, I am using WSL.

I followed your instructions. I made to the python local.py part (I did not use docker). So the website opens in Firefox under the url http://localhost:8080/ but somehow I get the error: "Access to this resource is forbidden."
Here is how I am using your config file. I am using Dropbox, so I set the storage_backend_to_use to "Dropbox". I set up the app in Dropbox giving me access only to that folder and generated an access token which I pasted in the storage_backends part. I set the path to point to the file in that specific folder. In the users section, I entered random new credentials. In the secret_key section, I entered a random Unicode. the auth_backend_to_use is set to "DictAuth".

The logs say the following:
127.0.0.1 - - [21/Jan/2021 17:36:40] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [21/Jan/2021 17:36:40] "GET /favicon.png HTTP/1.1" 200 -
127.0.0.1 - - [21/Jan/2021 17:36:40] "GET /favicon.ico HTTP/1.1" 200 -

Any idea what I might be doing wrong?
Cheers,
Ed

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.