Skip to content

Commit

Permalink
Add support for multiple CalDav servers (#3)
Browse files Browse the repository at this point in the history
* Added support for multiple servers
  • Loading branch information
tenJirka authored Sep 6, 2023
1 parent 8db9483 commit f135194
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 45 deletions.
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ reGenda is **read only** (for now) agenda app for reMarkable tablets. I would li

**Currently, reGenda only works with caldav servers that require login, such as [Nextcloud](https://nextcloud.com/) (only tested with Nextcloud so far). Other calendars specified by url or Google calendar for example are not supported and I don't guarantee they will be, but I know they might be more attractive to others.**

**Please do not use calendars with the same names, this will confuse the app.**

## What it can do

- Show your day based agenda
- Show event details
- Show events from multiple calendars (but not from multiple servers)
- You can choose what calendar will be displayed
- Show events from multiple calendars
- You can choose which calendar will be displayed
- You can choose language of UI (only English and Czech are currently supported)
- Fast time travel by selecting day from month based view
- Fast return to today
- Show events from multiple caldav servers

Maybe more, check preview or try it your self.

Expand Down Expand Up @@ -101,13 +104,13 @@ git pull
## Configuration
Server that reGegenda communicates with can't be set up from UI, so you **have to** edit config file before using it.
Servers that reGegenda communicates with can't be set up from UI, so you **have to** edit config file before using it.

This should be necessary to do only once.

Config file destination should be `/opt/etc/reGenda/config.yml`. Default location of example config file is `/opt/etc/reGenda/config.yml.example`.

If you are installing from package, post install script will create config file for you if not exists yet, but you have to fill informations about your server and your user.
If you are installing from package, post install script will create config file for you if not exists yet, but you have to fill informations about your servers and your users.

You can do this by this command:

Expand All @@ -118,10 +121,18 @@ nano /opt/etc/reGenda/config.yml # or different text editor like vim
Your configuration file should look like this:

```yaml
server:
url: "caldav url"
user: "user name"
password: "user password"
timezone: UTC # see https://mljar.com/blog/list-pytz-timezones/ for all available timezones
sources:
Personal: # Name of server (can be anything, but have to be unique in this config)
type: server # Just keep this, it's preparation for calendars specified by url
user: "your user name"
url: "your server url"
password: "your password"
#Work: # Another server or just different user
# type: server
# user: "your user name"
# url: "your server url"
# password: "your password"
```

## FAQ
Expand Down
2 changes: 1 addition & 1 deletion calendar_caldav.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

class Calendar:
"""
Represents one calendar that will be loaded.
Represents one server that will be loaded.
"""
def __init__(self, url, user, password):
with caldav.DAVClient(
Expand Down
17 changes: 12 additions & 5 deletions config.yml.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
timezone: UTC
server:
url: "caldav url"
user: "user name"
password: "user password"
timezone: UTC # see https://mljar.com/blog/list-pytz-timezones/ for all available timezones
sources:
Personal: # Name of server (can be anything, but have to be unique in this config)
type: server # Just keep this, it's preparation for calendars specified by url
user: "your user name"
url: "your server url"
password: "your password"
#Work: # Another server or just different user
# type: server
# user: "your user name"
# url: "your server url"
# password: "your password"
84 changes: 53 additions & 31 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def unexpectedCrashScene():
scene.display()


def settings(principal):
def settings(principals):
"""
Settings scene
"""
Expand All @@ -152,13 +152,17 @@ def settings(principal):
toshow = []
else:
toshow=config['toshow']
for event in toshow:
if event not in principal.calendar_list:
toshow.remove(event)

calendar_list = [ y for x in principals for y in x.calendar_list]

for calendar_name in toshow:
if calendar_name not in calendar_list:
toshow.remove(calendar_name)

while(True):
widgets = []
widgets.append(Label(200, 150, 150, 400, LANGUAGE.allCals, fontSize=40, justify="left"))
widgets = widgets + createButtonArray(principal.calendar_list, "calendar", x=250, y=widgets[-1].y + 50, fontSize=30)
widgets = widgets + createButtonArray(calendar_list, "calendar", x=250, y=widgets[-1].y + 50, fontSize=30)
widgets.append(Label(200, widgets[-2].y + 150, 150, 400, LANGUAGE.calsToSee, fontSize=40))
widgets.append(FontSize(30))
widgets = widgets + createListOfLabels(toshow, x=250, y=widgets[-2].y + 50)
Expand All @@ -177,10 +181,10 @@ def settings(principal):
selected = word
break
index = int(selected.replace('calendar', ''))
if principal.calendar_list[index] in toshow:
toshow.remove(principal.calendar_list[index])
if calendar_list[index] in toshow:
toshow.remove(calendar_list[index])
else:
toshow.append(principal.calendar_list[index])
toshow.append(calendar_list[index])
toshow.sort()
elif "czech" in output:
config['language'] = "czech"
Expand All @@ -200,13 +204,15 @@ def settings(principal):
yaml.dump(config, file)


def selectCalendars(principal, names):
def selectCalendars(principals, names):
"""
Gets lists of calendar and then initialize related calendar connections
"""
calendars = []
for calendar in names:
calendars.append(principal.principal.calendar(name=calendar))
for principal in principals:
for calendar in names:
if calendar in principal.calendar_list:
calendars.append(principal.principal.calendar(name=calendar))
return calendars


Expand All @@ -217,21 +223,24 @@ def connect():
with open(CONFIG_FILE, 'r') as file:
config = yaml.safe_load(file)

server = config['server']
try:
kalendar = calendar_caldav.Calendar(server['url'], server['user'], server['password'])
except caldav.lib.error.AuthorizationError:
scene = Scene(timeOut=1)
scene.add(Label(150, 150, 150, 400, LANGUAGE.loginFailed, fontSize=30))
scene.display()
exit()
except:
scene = Scene()
scene.add(Label(150, 150, 150, 400, LANGUAGE.somethingError, fontSize=30))
scene.add(Button(1000, 1500, 400, 50, LANGUAGE.retry))
scene.display()
kalendar = connect()
return kalendar
servers = config['sources']
calendars = []
for server in servers:
try:
calendar = calendar_caldav.Calendar(servers[server]['url'], servers[server]['user'], servers[server]['password'])
calendars.append(calendar)
except caldav.lib.error.AuthorizationError:
scene = Scene(timeOut=1)
scene.add(Label(150, 150, 150, 400, LANGUAGE.loginFailed, fontSize=30))
scene.display()
exit()
except:
scene = Scene()
scene.add(Label(150, 150, 150, 400, LANGUAGE.somethingError, fontSize=30))
scene.add(Button(1000, 1500, 400, 50, LANGUAGE.retry))
scene.display()
calendar = connect()
return calendars


def getEvents(start, toshow):
Expand Down Expand Up @@ -412,14 +421,14 @@ def dayAgenda():
config = yaml.safe_load(file)
start = datetime.date.today()

kalendar = connect()
principals = connect()

if 'toshow' not in config:
settings(kalendar)
settings(principals)
with open(CONFIG_FILE, 'r') as file:
config = yaml.safe_load(file)

toshow = selectCalendars(kalendar, config['toshow'])
toshow = selectCalendars(principals, config['toshow'])

dayScene = Scene()
dayScene.add(Button(1404 - int(len(LANGUAGE.settings)*35*6/11) - 50, 50, int(len(LANGUAGE.settings)*35*6/11), 50, LANGUAGE.settings, id="settings", fontSize=35, justify="left"))
Expand Down Expand Up @@ -490,10 +499,10 @@ def dayAgenda():
continue
start = datetime.date(pick[2], pick[1], pick[0])
elif "settings" == tmpDayScene.input[0]:
settings(kalendar)
settings(principals)
with open(CONFIG_FILE, 'r') as file:
config = yaml.safe_load(file)
toshow = selectCalendars(kalendar, config['toshow'])
toshow = selectCalendars(principals, config['toshow'])
else:
eventDetails(events[int(tmpDayScene.input[0])])
reload = False
Expand Down Expand Up @@ -530,6 +539,19 @@ def main():
scene.display()
exit()

# Convert old style server settings to new style
if "server" in config:
print("Converting old config")
config_old=deepcopy(config)
del config["server"]
old_server = {
'server': config_old['server']
}
old_server['server']['type'] = "server"
config['sources'] = old_server
with open(CONFIG_FILE, 'w') as file:
yaml.dump(config, file)

# Setting up language
if "language" not in config:
LANGUAGE = languages.english
Expand Down

0 comments on commit f135194

Please sign in to comment.