Skip to content

Commit aaf43f7

Browse files
committed
lint & template fixes
1 parent 31d8f9a commit aaf43f7

24 files changed

+200
-81
lines changed

.github/workflows/lint.yml

-1
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,3 @@ jobs:
5050
yamllint --version
5151
yamllint .
5252
shell: bash
53-

.github/workflows/release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
on:
44
push:
55
tags:
6-
- '*'
6+
- '*'
77

88
jobs:
99
publish:

.github/workflows/test.yml

+16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ jobs:
3838
pip install -r requirements.txt
3939
shell: bash
4040

41+
- name: Testing DB migrations for errors
42+
run: |
43+
python3 manage.py makemigrations
44+
python3 manage.py migrate
45+
shell: bash
46+
working-directory: ansible-webui/
47+
48+
- name: Testing DB migrations for warnings
49+
run: |
50+
m1=$(python3 manage.py makemigrations 2>&1)
51+
if echo "$m1" | grep -q 'WARNING'; then exit 1;fi
52+
m2=$(python3 manage.py migrate 2>&1)
53+
if echo "$m2" | grep -q 'WARNING'; then exit 1;fi
54+
shell: bash
55+
working-directory: ansible-webui/
56+
4157
- name: Running Tests
4258
run: python3 -m pytest
4359
shell: bash

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
dist/
33
venv/
44
ansible_webui.egg-info/
5-
__pychache__.py
5+
__pychache__.py
6+
**/aw.db

.pylintrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ ignore=CVS
5252
# ignore-list. The regex matches against paths and can be in Posix or Windows
5353
# format. Because '\\' represents the directory delimiter on Windows systems,
5454
# it can't be used as an escape character.
55-
ignore-paths=
55+
ignore-paths=venv/*
5656

5757
# Files or directories matching the regular expression patterns are skipped.
5858
# The regex matches against base names, not paths. The default value ignores

.yamllint

+3
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ rules:
77
allowed-values: ['true', 'false', 'yes', 'no']
88
line-length:
99
max: 160
10+
11+
ignore: |
12+
venv/*

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Ansible WebUI
22

3+
[![Documentation](https://readthedocs.org/projects/ansible-webui/badge/?version=latest)](https://ansible-webui.readthedocs.io/en/latest/?badge=latest)
4+
[![Lint](https://github.com/ansibleguy/ansible-webui/actions/workflows/lint.yml/badge.svg)](https://github.com/ansibleguy/ansible-webui/actions/workflows/lint.yml)
5+
[![Test](https://github.com/ansibleguy/ansible-webui/actions/workflows/test.yml/badge.svg)](https://github.com/ansibleguy/ansible-webui/actions/workflows/test.yml)
6+
37
This project was inspired by [ansible-semaphore](https://github.com/ansible-semaphore/semaphore).
48

59
The goal is to allow users to quickly install a WebUI for using Ansible locally.
@@ -27,6 +31,12 @@ python3 -m ansible-webui
2731

2832
----
2933

34+
## Usage
35+
36+
[Documentation](http://ansible-webui.readthedocs.io/)
37+
38+
----
39+
3040
## Contribute
3141

3242
Feel free to contribute to this project using [pull-requests](https://github.com/ansibleguy/ansible-webui/pulls), [issues](https://github.com/ansibleguy/ansible-webui/issues) and [discussions](https://github.com/ansibleguy/ansible-webui/discussions)!

ansible-webui/__init__.py

+3-42
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,6 @@
22

33

44
if __name__ == '__main__':
5-
import signal
6-
from platform import uname
7-
from threading import Thread
8-
from os import getpid, environ
9-
from os import kill as os_kill
10-
from time import sleep
11-
12-
from gunicorn.arbiter import Arbiter
13-
14-
from aw.config.main import init_globals
15-
init_globals()
16-
17-
from base.webserver import create_webserver
18-
from base.scheduler import Scheduler
19-
20-
if uname().system.lower() != 'linux':
21-
raise SystemError('Currently only linux systems are supported!')
22-
23-
scheduler = Scheduler()
24-
schedulerThread = Thread(target=scheduler.start)
25-
webserver = create_webserver()
26-
27-
# override gunicorn signal handling to allow for graceful shutdown
28-
def signal_exit(signum=None, stack=None):
29-
scheduler.stop(signum)
30-
os_kill(getpid(), signal.SIGQUIT) # trigger 'Arbiter.stop'
31-
sleep(5)
32-
exit(0)
33-
34-
def signal_reload(signum=None, stack=None):
35-
scheduler.reload(signum)
36-
37-
Arbiter.SIGNALS.remove(signal.SIGHUP)
38-
Arbiter.SIGNALS.remove(signal.SIGINT)
39-
Arbiter.SIGNALS.remove(signal.SIGTERM)
40-
41-
signal.signal(signal.SIGHUP, signal_reload)
42-
signal.signal(signal.SIGINT, signal_exit)
43-
signal.signal(signal.SIGTERM, signal_exit)
44-
45-
schedulerThread.start()
46-
webserver.run()
5+
# pylint: disable=E0401
6+
from main import main
7+
main()

ansible-webui/aw/config/hardcoded.py

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
ENV_KEY_DEV = 'AW_DEV'
99
THREAD_JOIN_TIMEOUT = 3
1010
RELOAD_INTERVAL = 10
11+
LOGIN_PATH = '/accounts/login/'

ansible-webui/aw/model/base.py

-2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,3 @@ class BareModel(models.Model):
1212

1313
class Meta:
1414
abstract = True
15-
16-

ansible-webui/aw/model/job.py

+35-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django.db import models
22
from django.conf import settings
3+
from django.contrib.auth.models import Group
34

45
from crontab import CronTab
56

@@ -13,14 +14,45 @@ class JobError(BareModel):
1314
logfile = models.FilePathField()
1415

1516

17+
class JobPermission(BareModel):
18+
field_list = ['name', 'permission', 'users', 'groups']
19+
20+
name = models.CharField(max_length=100)
21+
permission = models.CharField(
22+
max_length=50,
23+
choices=[('all', 'Full'), ('read', 'Read'), ('write', 'Write'), ('execute', 'Execute')],
24+
)
25+
users = models.ManyToManyField(
26+
settings.AUTH_USER_MODEL,
27+
through='JobPermissionMemberUser',
28+
through_fields=('permission', 'user'),
29+
)
30+
groups = models.ManyToManyField(
31+
Group,
32+
through='JobPermissionMemberGroup',
33+
through_fields=('permission', 'group'),
34+
)
35+
36+
37+
class JobPermissionMemberUser(BareModel):
38+
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
39+
permission = models.ForeignKey(JobPermission, on_delete=models.CASCADE)
40+
41+
42+
class JobPermissionMemberGroup(BareModel):
43+
group = models.ForeignKey(Group, on_delete=models.CASCADE)
44+
permission = models.ForeignKey(JobPermission, on_delete=models.CASCADE)
45+
46+
1647
class Job(BareModel):
17-
field_list = ['inventory', 'playbook', 'schedule', 'name', 'job_id']
48+
field_list = ['job_id', 'inventory', 'playbook', 'schedule', 'name', 'permission']
1849

50+
job_id = models.PositiveIntegerField(primary_key=True)
1951
inventory = models.CharField(max_length=150)
2052
playbook = models.CharField(max_length=150)
2153
schedule = models.CharField(max_length=50, validators=[CronTab])
2254
name = models.CharField(max_length=100)
23-
job_id = models.PositiveIntegerField(max_length=50)
55+
permission = models.ForeignKey(JobPermission, on_delete=models.SET_NULL, null=True)
2456

2557

2658
class JobExecution(BareModel):
@@ -31,7 +63,7 @@ class JobExecution(BareModel):
3163
]
3264

3365
user = models.ForeignKey(
34-
settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, blank=True, null=True,
66+
settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, null=True,
3567
related_name=f"jobexec_fk_user"
3668
)
3769
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name=f"jobexec_fk_job")

ansible-webui/aw/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from aw.model.job import JobError, JobExecution, Job
1+
from aw.model.job import JobError, JobExecution, Job, JobPermission, JobPermissionMemberGroup, JobPermissionMemberUser

ansible-webui/aw/route.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.contrib.auth.decorators import login_required, user_passes_test
22
from django.shortcuts import HttpResponse, redirect
33

4+
from aw.config.hardcoded import LOGIN_PATH
45
from aw.permission import authorized_to_access, authorized_to_exec, authorized_to_write
56

67

@@ -10,32 +11,32 @@ def _deny(request) -> (bool, HttpResponse):
1011

1112

1213
@login_required
13-
@user_passes_test(authorized_to_access, login_url='/')
14+
@user_passes_test(authorized_to_access, login_url=LOGIN_PATH)
1415
def ui(request, **kwargs):
1516
bad, deny = _deny(request)
1617
if bad:
1718
return deny
1819

1920
if request.method == 'POST':
20-
return ui_write
21+
return ui_write(request)
2122

2223
if request.method == 'PUT':
23-
return ui_write
24+
return ui_exec(request)
2425

2526
return HttpResponse(status=200, content=b"OK - read")
2627

2728

2829
@login_required
29-
@user_passes_test(authorized_to_write, login_url='/')
30+
@user_passes_test(authorized_to_write, login_url=LOGIN_PATH)
3031
def ui_write(request, **kwargs):
3132
return HttpResponse(status=200, content=b"OK - write")
3233

3334

3435
@login_required
35-
@user_passes_test(authorized_to_exec, login_url='/')
36+
@user_passes_test(authorized_to_exec, login_url=LOGIN_PATH)
3637
def ui_exec(request, **kwargs):
3738
return HttpResponse(status=200, content=b"OK - exec")
3839

3940

4041
def catchall(request, **kwargs):
41-
return redirect('/accounts/login/')
42+
return redirect(LOGIN_PATH)

ansible-webui/aw/settings.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
from os import environ
44

55
# Build paths inside the project like this: BASE_DIR / 'subdir'.
6-
BASE_DIR = Path(__file__).resolve()
6+
BASE_DIR = Path(__file__).resolve().parent.parent
77

88
from aw.config.main import config
9+
from aw.config.hardcoded import ENV_KEY_DEV, LOGIN_PATH
910

1011

12+
DEBUG = ENV_KEY_DEV in environ
1113
ALLOWED_HOSTS = ['*']
14+
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
1215

1316
# Application definition
1417
INSTALLED_APPS = [
@@ -83,9 +86,9 @@
8386

8487
# Static files (CSS, JavaScript, Images)
8588
STATIC_URL = '/static/'
86-
STATICFILES_DIRS = [os_path.join(BASE_DIR, 'static/')]
89+
STATICFILES_DIRS = [BASE_DIR / 'aw' / 'static']
8790
LOGIN_REDIRECT_URL = '/ui/'
88-
LOGOUT_REDIRECT_URL = '/accounts/login/'
91+
LOGOUT_REDIRECT_URL = LOGIN_PATH
8992
handler403 = 'aw.utils.handlers.handler403'
9093
handler500 = 'aw.utils.handlers.handler500'
9194

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<noscript>
22
<div class="alert alert-danger">
3-
<strong>You must enable javascript to use this webinterface.</strong>
3+
<strong>You have to enable javascript for the App to work!</strong>
44
</div>
55
</noscript>

ansible-webui/aw/templates/head.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
{% if request.user_agent.is_mobile %}
1515
<meta name="viewport" content="width=640"/>
1616
{% endif %}
17-
<link rel="icon" type="image/jpg" href="{% static 'img/ansible.svg' %}">
17+
<link rel="icon" type="image/svg" href="{% static 'img/ansible.svg' %}">
1818

1919
{% load bootstrap5 %}
2020
{% bootstrap_javascript %}

ansible-webui/aw/templates/registration/login.html

+1-10
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121
{% endfor %}
2222
{% endif %}
2323
<div class="alert alert-info">
24-
{% if user.is_authenticated %}
25-
Your account doesn't have access to this page. To proceed,
26-
please login with an account that has access.
27-
{% else %}
24+
{% if not user.is_authenticated %}
2825
Please login to see this page.
2926
{% endif %}
3027
</div>
@@ -43,11 +40,5 @@
4340
<br>
4441
<button type="submit" value="login" class="btn btn-secondary">Login</button>
4542
</form>
46-
<div class="alert alert-info aw-info-special-mode">
47-
<strong>This is the GrowAutomation Beta-System</strong><br>
48-
You can get access to this preview by supporting our cause:<br>
49-
<a href="https://github.com/sponsors/ansibleguy">Sponsor</a>
50-
</div>
51-
{% endif %}
5243
</div>
5344
{% endblock %}

ansible-webui/aw/templatetags/util.py

+26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
1+
from django import template
2+
13
from aw.config.hardcoded import VERSION
24

35

6+
register = template.Library()
7+
8+
9+
@register.simple_tag
410
def get_version() -> str:
511
return VERSION
12+
13+
14+
@register.simple_tag
15+
def set_var(val):
16+
return val
17+
18+
19+
@register.filter
20+
def get_full_uri(request):
21+
return request.build_absolute_uri()
22+
23+
24+
# @register.filter
25+
# def format_ts(datetime_obj):
26+
# return datetime.strftime(datetime_obj, config.DATETIME_TS_FORMAT)
27+
28+
29+
# @register.simple_tag
30+
# def random_gif() -> str:
31+
# return f"img/500/{randint(1, 20)}.gif"

ansible-webui/aw/utils/util_test.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
3+
def test_dummy():
4+
pass

0 commit comments

Comments
 (0)