Skip to content

Commit

Permalink
Sync test
Browse files Browse the repository at this point in the history
* First version of URL builder (#3)

* Updated API docs

* Added option for default notification service (#56)

* Added support for args in URL Builder (#3)

* Added regex checks in URL builder (#3)

* Added test button when adding notification service

* Updated API docs

* Added recurring reminders on week days (#55)

* Updated API docs
  • Loading branch information
Casvt authored Mar 11, 2024
1 parent 0cc53f3 commit 0b67ca1
Show file tree
Hide file tree
Showing 11 changed files with 996 additions and 0 deletions.
152 changes: 152 additions & 0 deletions backend/notification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,158 @@ def get_apprise_services() -> List[Dict[str, Union[str, Dict[str, list]]]]:

return apprise_services

def _sort_tokens(t: dict) -> int:
result = [
int(not t['required'])
]

if t['type'] == 'choice':
result.append(0)
elif t['type'] != 'list':
result.append(1)
else:
result.append(2)

return result

def get_apprise_services() -> List[Dict[str, Union[str, Dict[str, list]]]]:
apprise_services = []
raw = Apprise().details()
for entry in raw['schemas']:
entry: Dict[str, Union[str, dict]]
result: Dict[str, Union[str, Dict[str, list]]] = {
'name': str(entry['service_name']),
'doc_url': entry['setup_url'],
'details': {
'templates': entry['details']['templates'],
'tokens': [],
'args': []
}
}

schema = entry['details']['tokens']['schema']
result['details']['tokens'].append({
'name': schema['name'],
'map_to': 'schema',
'required': schema['required'],
'type': 'choice',
'options': schema['values'],
'default': schema.get('default')
})

handled_tokens = {'schema'}
result['details']['tokens'] += [
{
'name': v['name'],
'map_to': k,
'required': v['required'],
'type': 'list',
'delim': v['delim'][0],
'content': [
{
'name': content['name'],
'required': content['required'],
'type': content['type'],
'prefix': content.get('prefix'),
'regex': content.get('regex')
}
for content, _ in ((entry['details']['tokens'][e], handled_tokens.add(e)) for e in v['group'])
]
}
for k, v in
filter(
lambda t: t[1]['type'].startswith('list:'),
entry['details']['tokens'].items()
)
]
handled_tokens.update(
set(map(lambda e: e[0],
filter(lambda e: e[1]['type'].startswith('list:'),
entry['details']['tokens'].items())
))
)

result['details']['tokens'] += [
{
'name': v['name'],
'map_to': k,
'required': v['required'],
'type': v['type'].split(':')[0],
**({
'options': v.get('values'),
'default': v.get('default')
} if v['type'].startswith('choice') else {
'prefix': v.get('prefix'),
'min': v.get('min'),
'max': v.get('max'),
'regex': v.get('regex')
})
}
for k, v in
filter(
lambda t: not t[0] in handled_tokens,
entry['details']['tokens'].items()
)
]

result['details']['tokens'].sort(key=_sort_tokens)

result['details']['args'] += [
{
'name': v.get('name', k),
'map_to': k,
'required': v.get('required', False),
'type': v['type'].split(':')[0],
**({
'delim': v['delim'][0],
'content': []
} if v['type'].startswith('list') else {
'options': v['values'],
'default': v.get('default')
} if v['type'].startswith('choice') else {
'default': v['default']
} if v['type'] == 'bool' else {
'min': v.get('min'),
'max': v.get('max'),
'regex': v.get('regex')
})
}
for k, v in
filter(
lambda a: (
a[1].get('alias_of') is None
and not a[0] in ('cto', 'format', 'overflow', 'rto', 'verify')
),
entry['details']['args'].items()
)
]
result['details']['args'].sort(key=_sort_tokens)

apprise_services.append(result)

apprise_services.sort(key=lambda s: s['name'].lower())

apprise_services.insert(0, {
'name': 'Custom URL',
'doc_url': 'https://github.com/caronc/apprise#supported-notifications',
'details': {
'templates': ['{url}'],
'tokens': [{
'name': 'Apprise URL',
'map_to': 'url',
'required': True,
'type': 'string',
'prefix': None,
'min': None,
'max': None,
'regex': None
}],
'args': []
}
})

return apprise_services

class NotificationService:
def __init__(self, user_id: int, notification_service_id: int) -> None:
self.id = notification_service_id
Expand Down
6 changes: 6 additions & 0 deletions backend/reminders.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ def update(
Either repeat_quantity and repeat_interval are given, weekdays is
given or neither, but not both.
Note about args:
Either repeat_quantity and repeat_interval are given, weekdays is given or neither, but not both.
Raises:
NotificationServiceNotFound: One of the notification services was not found.
InvalidKeyValue: The value of one of the keys is not valid or
Expand Down Expand Up @@ -510,6 +513,9 @@ def add(
Either repeat_quantity and repeat_interval are given,
weekdays is given or neither, but not both.
Note about args:
Either repeat_quantity and repeat_interval are given, weekdays is given or neither, but not both.
Raises:
NotificationServiceNotFound: One of the notification services was not found.
InvalidKeyValue: The value of one of the keys is not valid
Expand Down
6 changes: 6 additions & 0 deletions frontend/static/css/info.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@
.form-container > form .repeat-options > button {
width: calc((100% / 3) - (var(--gap) / 1.5));
min-width: min-content;
<<<<<<< HEAD
=======
padding: 1rem 0rem;
>>>>>>> Development
}

.repeat-bar {
Expand Down Expand Up @@ -224,7 +227,10 @@ div.options > button {
.sub-inputs > input,
.sub-inputs > select,
.sub-inputs > button,
<<<<<<< HEAD
=======
.sub-inputs > label,
>>>>>>> Development
.form-container > form .repeat-options > button {
width: 100%;
}
Expand Down
152 changes: 152 additions & 0 deletions frontend/static/css/notification.css
Original file line number Diff line number Diff line change
Expand Up @@ -249,24 +249,173 @@ tr:has(input:read-only) button[data-type="save"] {
display: none;
}

<<<<<<< HEAD
/* */
/* Add service */
/* */
#add-service-container {
display: none;
}

.overflow-container.show-add #add-service-container {
display: block;
}

.overflow-container.show-add > table {
display: none;
}

#service-list {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
}

#service-list button {
width: max(30%, 10rem);
height: 6rem;

display: flex;
justify-content: center;
align-items: center;

padding: .75rem;
border-radius: 4px;
border: 2px solid var(--color-gray);

text-align: center;
font-size: 1.1rem;
}

#add-service-container.show-add-window #add-service-window {
display: flex;
}

#add-service-container.show-add-window #service-list {
display: none;
}

/* */
/* Add service form */
/* */
#add-service-window {
max-width: 30rem;
margin: auto;

display: none;
flex-direction: column;
justify-content: center;
gap: 1rem;

text-align: center;
}

#add-service-window > h3 {
font-size: 1.75rem;
}

#add-service-window > p {
margin-bottom: calc((1rem + 2px) * -1);

border: 2px solid var(--color-gray);
border-top-left-radius: 4px;
border-top-right-radius: 4px;
padding: .75rem 1rem;
color: var(--color-gray);

text-align: left;

box-shadow: var(--default-shadow);
}

#add-service-window > button {
border-radius: 4px;
border: 2px solid var(--color-gray);
padding: .75rem;
}

#add-service-window > a,
#add-service-window > p > a {
color: var(--color-light);
}

#add-service-window > div[data-map],
#add-service-window > div[data-map] > .entries-list {
display: flex;
flex-direction: column;
gap: inherit;
}

#add-service-window > div[data-map] {
padding: .5rem;
border: 2px solid var(--color-gray);
border-radius: 4px;
box-shadow: var(--default-shadow);
}

#add-service-window > div[data-map] > p {
color: var(--color-gray);
font-size: 1.1rem;
}

.entries-list {
min-height: 5rem;
max-height: 15rem;
overflow-y: auto;

align-items: center;

background-color: var(--color-dark);
color: var(--color-light);
border: 2px solid var(--color-gray);
border-radius: 4px;
padding: .75rem;
box-shadow: var(--default-shadow);

font-size: 1rem;
}

.entries-list > p:first-child {
color: var(--color-gray);
font-size: 1.1rem;
}

.input-entries:not(:has(div)) {
display: none;
}

.add-row {
height: 2rem;
width: 80%;

display: flex;
=======
.add-row {
width: min(100%, 21rem);

display: flex;
justify-content: center;
flex-wrap: wrap;
>>>>>>> Development
gap: 1rem;
}

.add-row input {
flex-grow: 1;
<<<<<<< HEAD
=======
height: 2rem;
min-width: 0rem;
>>>>>>> Development
font-size: .8rem;
}

.add-row button {
<<<<<<< HEAD
=======
height: 2rem;
>>>>>>> Development
padding: .35rem .75rem;
background-color: var(--color-gray);
border-radius: 4px;
Expand All @@ -291,9 +440,12 @@ tr:has(input:read-only) button[data-type="save"] {
height: inherit;
fill: var(--color-dark);
}
<<<<<<< HEAD
=======

@media (max-width: 543px) {
#service-list button {
flex-grow: 1;
}
}
>>>>>>> Development
Loading

0 comments on commit 0b67ca1

Please sign in to comment.