I have been able to successfully hack together a python script which runs on my nextcloud server once daily using cron, and can reset one or more task lists on a daily basis. One clear weakness of this method is that it relies on connecting to the server as a user, so this is not suitable for large deployments, or for use cases where passwords are not known. However, the same script should work when run from a machine other than the server, so for anyone who is a user of a nextcloud instance where they do not have any admin access, this same method should allow one to fake repeating daily tasks.
For now, I am just providing the methods I used to set this up on my machine, if there is interest, I can start a github project and do some development in hopes of supporting other deployments or use cases.
Requirements:
- Python >= 3.4, with venv module installed system-wide
- cron
Steps:
-
mkdir /home/username/autoreset-tasks
Create a folder to contain all of the relevant files. In my case, I named this folder autoreset-tasks, and put it in my home directory, but you can use any location you like. After switching to this folder ( cd /home/username/autoreset-tasks ), all other commands can run from this location.
-
python3 -m venv venv
Create a python virtual environment (venv) to install the required libraries, without affecting system files, or requiring root access. I named mine venv (last argument in the command above), but you can use whatever name you like
-
./venv/bin/pip3 install caldav-tasks-api
Install the required library for CLI communication with a CalDAV server. See: GitHub - thiswillbeyourgithub/Caldav-Tasks-API: Python library and CLI for managing CalDAV tasks (VTODOs), supporting Nextcloud and other CalDAV servers with robust X-property handling. , caldav-tasks-api · PyPI
-
Using the standard Nextcloud web interface, or any other interface you wish, create a new tasks list (Daily Tasksin this example). All tasks in this list will be reset daily.
-
Create a script which will use the installed library to reset task lists. In my case, this is reset.py, given in full below. If you know Python, feel free to extend the functionality to suit your own use case.
-
touch server.conf
Create the associated configuration file (server.conf) which contains the credentials and task list names to be reset.
-
chmod 600 server.conf
Protect server.conffrom being read by other users, since it will contain plaintext credentials. Is this an ideal security method? Definitely not. However, it is in-line with nextcloud’s own security model, in which passwords for the database are stored in config.php in plaintext. And if an attacker can read a file which is read-protected and only available to a single user, they can do it as the webserver’s user as well, and all the data is compromised anyway. In my case, I don’t directly expose my nextcloud server to the internet, so I think the worry here is comparatively low
-
Update the contents of server.conf to match the users and task lists which should reset daily. An example for the Daily Taskslist is given below.
-
At this point, you should be able to reset all tasks on the Daily Tasks list with the command /home/username/autoreset-tasks/venv/bin/python3 /home/username/autoreset-tasks/reset.py. Test this out a couple of times by manually adding, removing, completing tasks, and verifying that everything is reset as expected.
-
Runcrontab -eto create a cron entry for this job. To reset tasks daily, this job should run once every day at the same time. On my server, which has a 5-part cron scheduler, this looks like:
m h dom mon dow command
0 1 * * * /home/username/autoreset-tasks/venv/bin/python3 /home/username/autoreset-tasks/reset.py
to run the task every day at 1:00 am.
Optionally, you can add redirection to the command to use a custom log file for standard output and/or standard error.
# reset.py
import datetime
from caldav_tasks_api import TasksAPI
from caldav_tasks_api.utils.data import TaskData
class User:
def __init__(self):
self.name = ""
self.pw = ""
self.lists = []
def complete(self):
return self.name != ""
def __str__(self):
return(
f"<User Name:'{self.name}', Pass:'********', "
f"Lists: {len(self.lists)}: {self.lists}>"
)
# Print date and time
now = datetime.datetime.now()
print(now)
# Load relevant data from config
users = []
user = User()
with open("/home/username/autoreset-tasks/server.conf", "r") as file:
for line in file:
# Trim whitespace, skip empty lines
line = line.strip()
if len(line) == 0: continue
# Comments begin with '#' as first non-whitespace character
if line[0] == '#': continue
# Tokenize on colon. Expect exactly two tokens, as each line
# should consist of a key-value pair
tokens = line.split(":")
if len(tokens) != 2:
# Report error
print ("Found line with " + len(tokens) + " tokens: " + line)
# Terminate
exit(1)
key = tokens[0].strip()
val = tokens[1].strip()
# Each name entry starts a new user
if key == "user":
# If we have a full user, add to object
if user.complete():
users.append(user)
# Since this starts a new user, create a new object
user = User()
user.name = val
# Only one possible password, overwrite previous values
if key == "pass":
user.pw = val
# Many possible lists, append all
if key == "lists":
lists = val.split(",")
for task_list in lists:
user.lists.append(task_list.strip())
if user.complete():
users.append(user)
for user in users:
print(user)
# Due to credentials, need to handle each user's task lists separately
for user in users:
# Connect to API
api = TasksAPI(
url="https://localhost:8443/nextcloud/remote.php/dav/", # DAV interface
username=user.name, # From config
password=user.pw, # From config
target_lists=user.lists, # Only lists which should reset daily
ssl_verify_cert=False # Needed if server is self-signed
)
# Load data from server
api.load_remote_data()
# Itereate through all lists
for task_list in api.task_lists:
# Iterate through all items in list
for task in task_list.tasks:
# Optional
# Check for task completion, if complete, log
# Reset task status
task.percent_complete = 0
task.completed = False
api.update_task(task)
print("Completed successfully")
# server.conf
# Comments begin with the '#' character
# Usernames, passwords, and list names which begin or end with spaces,
# or contain the character ':' are not supported. List names also cannot contain
# the character ','
# User name must be given first. Use the same username as for web access
user: name
# Use the same password as for web access
pass: secret
# Multiple lists can be provided in the same entry, separated by a comma
lists: my list, my other list
# Blank lines are ignored
lists: another list
# Leading whitespace is ignored, indent as you please
lists: list with whitespace
# Multiple users are supported. Specifying a new username starts a new
# set of lists
user: name2
lists: their list
# Password can come anywhere in the set of lists
pass: secret2