diff --git a/.env b/.env index fdd03ba..becebb1 100644 --- a/.env +++ b/.env @@ -34,6 +34,16 @@ EXPOSE_CERTS=/path/to/certs EXPOSE_DHPARAM=/path/to/dhparam #Superuser settings +SIRM_SUPER_USER=***** +SIRM_SUPER_PASSWORD=******* +SIRM_SUPER_EMAIL=*****@igp.gob.pe + +#Developer user settings +SIRM_DEV_USER=***** +SIRM_DEV_PASSWORD=******* +SIRM_DEV_EMAIL=*****@igp.gob.pe + +#Operator user settings SIRM_USER=***** SIRM_PASSWORD=******* SIRM_EMAIL=*****@igp.gob.pe \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 69d4ae7..7e11251 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -99,6 +99,12 @@ services: - EXPOSE_NAS=${EXPOSE_NAS} - PROC_SITE=${PROC_SITE} - SCHAIN_SITE=${SCHAIN_SITE} + - SIRM_SUPER_USER=${SIRM_SUPER_USER} + - SIRM_SUPER_PASSWORD=${SIRM_SUPER_PASSWORD} + - SIRM_SUPER_EMAIL=${SIRM_SUPER_EMAIL} + - SIRM_DEV_USER=${SIRM_DEV_USER} + - SIRM_DEV_PASSWORD=${SIRM_DEV_PASSWORD} + - SIRM_DEV_EMAIL=${SIRM_DEV_EMAIL} - SIRM_USER=${SIRM_USER} - SIRM_PASSWORD=${SIRM_PASSWORD} - SIRM_EMAIL=${SIRM_EMAIL} @@ -127,11 +133,11 @@ services: sirm-job: container_name: 'sirm-job' - image: mcuadros/ofelia:latest + image: mcuadros/ofelia:v0.3.6 depends_on: - sirm-web networks: - - frontend_sirm + #- frontend_sirm - backend_sirm command: daemon --docker volumes: diff --git a/setup/start_realtime.sh b/setup/start_realtime.sh index 6549c70..497d27b 100755 --- a/setup/start_realtime.sh +++ b/setup/start_realtime.sh @@ -25,8 +25,11 @@ if [ -f .gitkeep ]; touch .gitkeep fi -echo "Create Superuser" -python manage.py createsuperuser_if_none_exists +echo "Create Groups" +python manage.py create_groups + +echo "Create User" +python manage.py create_users echo "Run server" python manage.py runserver 0.0.0.0:8080 \ No newline at end of file diff --git a/volumes/sirm/apps/accounts/management/commands/create_groups.py b/volumes/sirm/apps/accounts/management/commands/create_groups.py new file mode 100644 index 0000000..bf37900 --- /dev/null +++ b/volumes/sirm/apps/accounts/management/commands/create_groups.py @@ -0,0 +1,71 @@ +from django.core.management import BaseCommand +from django.contrib.auth.models import User, Group , Permission +import logging + +GROUPS = { + "Developer": { + #General permissions + #"log entry" : ["add","delete","change","view"], + #"group" : ["add","delete","change","view"], + #"permission" : ["add","delete","change","view"], + #"user" : ["add","delete","change","view"], + #"content type" : ["add","delete","change","view"], + #"session" : ["add","delete","change","view"], + + #Specific permissions + "profile" : ["add","delete","change","view"], + "experiment" : ["add","delete","change","view"], + "configuration" : ["add","delete","change","view"], + "device" : ["add","delete","change","view"], + "device type" : ["add","delete","change","view"], + "generator configuration" : ["add","delete","change","view"], + "pedestal configuration" : ["add","delete","change","view"], + "usrprx configuration" : ["add","delete","change","view"], + "tx code" : ["add","delete","change","view"], + "usrptx configuration" : ["add","delete","change","view"], + }, + + "Operator": { + #Specific permissions + "profile" : ["view"], + "experiment" : ["view"], + "configuration" : ["view"], + "device" : ["view"], + "device type" : ["view"], + "generator configuration" : ["view"], + "pedestal configuration" : ["view"], + "usrprx configuration" : ["view"], + "tx code" : ["view"], + "usrptx configuration" : ["view"], + }, +} + +class Command(BaseCommand): + + help = "Creates read only default permission groups for users" + + def handle(self, *args, **options): + for group_name in GROUPS: + try: + Group.objects.get(name=group_name) + self.stdout.write(f'Local group "{group_name}" currently exists') + continue + except: + new_group = Group.objects.create(name=group_name) + # Loop models in group + for app_model in GROUPS[group_name]: + + # Loop permissions in group/model + for permission_name in GROUPS[group_name][app_model]: + + # Generate permission name as Django would generate it + name = "Can {} {}".format(permission_name, app_model) + self.stdout.write(f'Creating "{name}"') + + try: + model_add_perm = Permission.objects.get(name=name) + except Permission.DoesNotExist: + logging.warning("Permission not found with name '{}'.".format(name)) + continue + + new_group.permissions.add(model_add_perm) \ No newline at end of file diff --git a/volumes/sirm/apps/accounts/management/commands/create_users.py b/volumes/sirm/apps/accounts/management/commands/create_users.py new file mode 100644 index 0000000..ac886e9 --- /dev/null +++ b/volumes/sirm/apps/accounts/management/commands/create_users.py @@ -0,0 +1,60 @@ +import os +from django.core.management.base import BaseCommand +from django.contrib.auth.models import User, Group + +class Command(BaseCommand): + """ + Create a superuser and user if none exist + Example: + manage.py create_users + """ + + help = "Create a superuser and user if none exist" + + def handle(self, *args, **options): + + users = { + 'Superuser': { + 'username': os.environ.get('SIRM_SUPER_USER', 'superuser'), + 'password': os.environ.get('SIRM_SUPER_PASSWORD', 'SuperuseROJ'), + 'email' : os.environ.get('SIRM_SUPER_EMAIL', 'superuser@igp.gob.pe')}, + 'Developer': { + 'username': os.environ.get('SIRM_DEV_USER', 'developer'), + 'password': os.environ.get('SIRM_DEV_PASSWORD', 'DevelopeROJ'), + 'email' : os.environ.get('SIRM_DEV_EMAIL', 'developer@igp.gob.pe')}, + 'Operator': { + 'username': os.environ.get('SIRM_USER', 'operator'), + 'password': os.environ.get('SIRM_PASSWORD', 'OperatoROJ'), + 'email' : os.environ.get('SIRM_EMAIL', 'operator@igp.gob.pe')} + } + + for key, value in users.items(): + if key == 'Superuser': + if User.objects.filter(is_superuser=True): + self.stdout.write(f'Local {key} currently exists') + else: + user, created = User.objects.get_or_create(username=value["username"], first_name=value["username"], email=value["email"], is_superuser = True, is_staff = True) + if created: + user.set_password(value["password"]) + user.save() + self.stdout.write(f'Local {key} "{value["username"]}" was created') + else: + self.stdout.write(f'Unable to create this local superuser: "superuser already exists"') + else: + if User.objects.filter(groups__name=key): + if User.objects.filter(groups__name=key, is_superuser=True): + self.stdout.write(f"{key} group must not have a superuser, remove superusers and create a new user") + else: + self.stdout.write(f"Local {key} currently exists") + else: + user, created = User.objects.get_or_create(username=value["username"], first_name=value["username"], email=value["email"]) + if created: + user.set_password(value["password"]) + user.save() + self.stdout.write(f'Local {key} "{value["username"]}" was created') + + group = Group.objects.get(name=key) + group.user_set.add(user) + self.stdout.write(f'Local {key} "{value["username"]}" was added to {key} group') + else: + self.stdout.write(f'Unable to create and join to {key} group this local user: "user already exists"') \ No newline at end of file diff --git a/volumes/sirm/apps/accounts/management/commands/createsuperuser_if_none_exists.py b/volumes/sirm/apps/accounts/management/commands/createsuperuser_if_none_exists.py deleted file mode 100644 index 71d4585..0000000 --- a/volumes/sirm/apps/accounts/management/commands/createsuperuser_if_none_exists.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from django.core.management.base import BaseCommand -from django.contrib.auth import get_user_model - -class Command(BaseCommand): - """ - Create a superuser if none exist - Example: - manage.py createsuperuser_if_none_exists --user=admin123 --password=admin123 --email=admin123@igp.gob.pe - """ - - def handle(self, *args, **options): - - User = get_user_model() - username = os.environ.get('SIRM_USER', 'admin') - password = os.environ.get('SIRM_PASSWORD', 'soporte') - email = os.environ.get('SIRM_EMAIL', 'admin@igp.gob.pe') - - if User.objects.exists(): - self.stdout.write(f'Local user "{username}" currently exists') - return - - User.objects.create_superuser(username=username, password=password, email=email) - - self.stdout.write(f'Local user "{username}" was created') \ No newline at end of file diff --git a/volumes/sirm/apps/generator/views.py b/volumes/sirm/apps/generator/views.py index f6287ba..a0aee2f 100644 --- a/volumes/sirm/apps/generator/views.py +++ b/volumes/sirm/apps/generator/views.py @@ -12,6 +12,17 @@ from apps.main.views import sidebar from .models import GeneratorConfiguration from .forms import GeneratorConfigurationForm, GeneratorImportForm +def is_developer(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Developer' in groups or user.is_staff + return 'Developer' in groups or user.is_superuser + + +def is_operator(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Operator' in groups or user.is_staff + return 'Operator' in groups or user.is_superuser + def conf(request, conf_id): @@ -42,6 +53,10 @@ def conf_edit(request, conf_id): conf = get_object_or_404(GeneratorConfiguration, pk=conf_id) + if not is_developer(request.user): + messages.error(request, 'You must be an developer to edit this configuration') + return redirect(conf.get_absolute_url()) + if request.method=='GET': form = GeneratorConfigurationForm(instance=conf) diff --git a/volumes/sirm/apps/main/models.py b/volumes/sirm/apps/main/models.py index 4ae5eba..64a22c7 100644 --- a/volumes/sirm/apps/main/models.py +++ b/volumes/sirm/apps/main/models.py @@ -343,7 +343,7 @@ class Experiment(PolymorphicModel): self.reception_rx.stop_device() time.sleep(0.1) self.pedestal.reset_device() - time.sleep(14) + time.sleep(0.1) self.pedestal.stop_device() time.sleep(0.1) proc_url = 'http://'+os.environ['PROC_SITE']+'/stop' diff --git a/volumes/sirm/apps/main/views.py b/volumes/sirm/apps/main/views.py index 5904dd3..b1b2ab2 100644 --- a/volumes/sirm/apps/main/views.py +++ b/volumes/sirm/apps/main/views.py @@ -67,15 +67,15 @@ MIX_OPERATIONS = { def is_developer(user): - groups = [str(g.name) for g in user.groups.all()] - return 'Developer' in groups or user.is_staff + #return 'Developer' in groups or user.is_staff + return 'Developer' in groups or user.is_superuser def is_operator(user): - groups = [str(g.name) for g in user.groups.all()] - return 'Operator' in groups or user.is_staff + #return 'Operator' in groups or user.is_staff + return 'Operator' in groups or user.is_superuser def has_been_modified(model): @@ -135,6 +135,10 @@ def device(request, id_dev): @login_required def device_new(request): + + if not is_developer(request.user): + messages.error(request, 'You must be an developer to create a new experiment') + return redirect('url_devices') if request.method == 'GET': form = DeviceForm() @@ -160,6 +164,10 @@ def device_new(request): def device_edit(request, id_dev): device = get_object_or_404(Device, pk=id_dev) + + if not is_developer(request.user): + messages.error(request, 'You must be an developer to edit this object') + return redirect(device.get_absolute_url()) if request.method == 'GET': form = DeviceForm(instance=device) @@ -320,9 +328,9 @@ def experiment(request, id_exp): def experiment_new(request, id_camp=None): if not is_developer(request.user): - messages.error( - request, 'Developer required, to create new Experiments') - return redirect('index') + messages.error(request, 'You must be an developer to create a new experiment') + return redirect('url_experiments') + kwargs = {} if request.method == 'GET': @@ -348,8 +356,12 @@ def experiment_new(request, id_camp=None): @login_required def experiment_edit(request, id_exp): - experiment = get_object_or_404(Experiment, pk=id_exp) + + if not is_developer(request.user): + messages.error(request, 'You must be an developer to edit this experiment') + return redirect(experiment.get_absolute_url()) + id_p = experiment.pedestal_id id_rx = experiment.reception_rx_id id_tx = experiment.transmission_tx_id @@ -407,7 +419,7 @@ def experiment_delete(request, id_exp): experiment.delete() return redirect('url_experiments') - messages.error(request, 'Not enough permission to delete this object') + messages.error(request, 'Not enough permission to delete this experiment') return redirect(experiment.get_absolute_url()) kwargs = { @@ -472,6 +484,10 @@ def experiment_import(request, id_exp): def experiment_start(request, id_exp): exp = get_object_or_404(Experiment, pk=id_exp) + if not is_developer(request.user) and not is_operator(request.user): + messages.error(request, 'You must be an developer or operator to start this experiment') + return redirect(exp.get_absolute_url()) + if exp.status == 2: messages.warning(request, 'Experiment {} already runnnig'.format(exp.name)) else: @@ -492,7 +508,11 @@ def experiment_start(request, id_exp): def experiment_stop(request, id_exp): all_status = Experiment.objects.filter(status=2) exp = get_object_or_404(Experiment, pk=id_exp) - + + if not is_developer(request.user) and not is_operator(request.user): + messages.error(request, 'You must be an developer or operator to stop this experiment') + return redirect(exp.get_absolute_url()) + if exp.status == 2 or exp.status == 4 or exp.status == 5: for one_exp in all_status: if one_exp != exp: @@ -850,7 +870,7 @@ def dev_conf_new(request, id_exp=0, id_dev=0): if not is_developer(request.user): messages.error( request, 'Developer required, to create new configurations') - return redirect('index') + return redirect('url_dev_confs') initial = {} kwargs = {} @@ -939,6 +959,10 @@ def dev_conf_start(request, id_conf): conf = get_object_or_404(Configuration, pk=id_conf) + if not is_developer(request.user) and not is_operator(request.user): + messages.error(request, 'You must be an developer or operator to start this configuration') + return redirect(conf.get_absolute_url()) + if conf.start_device(): messages.success(request, conf.message) else: @@ -954,6 +978,10 @@ def dev_conf_stop(request, id_conf): conf = get_object_or_404(Configuration, pk=id_conf) + if not is_developer(request.user) and not is_operator(request.user): + messages.error(request, 'You must be an developer or operator to stop this configuration') + return redirect(conf.get_absolute_url()) + if conf.stop_device(): messages.success(request, conf.message) else: diff --git a/volumes/sirm/apps/pedestal/views.py b/volumes/sirm/apps/pedestal/views.py index 320081f..fb46227 100644 --- a/volumes/sirm/apps/pedestal/views.py +++ b/volumes/sirm/apps/pedestal/views.py @@ -12,6 +12,17 @@ from apps.main.views import sidebar from .models import PedestalConfiguration from .forms import PedestalConfigurationForm, PedestalImportForm +def is_developer(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Developer' in groups or user.is_staff + return 'Developer' in groups or user.is_superuser + + +def is_operator(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Operator' in groups or user.is_staff + return 'Operator' in groups or user.is_superuser + def conf(request, conf_id): @@ -45,6 +56,9 @@ def conf_edit(request, conf_id): conf = get_object_or_404(PedestalConfiguration, pk=conf_id) + if not is_developer(request.user): + messages.error(request, 'You must be an developer to edit this configuration') + return redirect(conf.get_absolute_url()) if request.method=='GET': @@ -119,6 +133,10 @@ def conf_reset(request, conf_id): conf = get_object_or_404(PedestalConfiguration, pk=conf_id) + if not is_developer(request.user) and not is_operator(request.user): + messages.error(request, 'You must be an developer or operator to reset this pedestal') + return redirect(conf.get_absolute_url()) + if conf.reset_device(): messages.success(request, conf.message) else: diff --git a/volumes/sirm/apps/usrp_rx/views.py b/volumes/sirm/apps/usrp_rx/views.py index 5507b8c..23afc36 100644 --- a/volumes/sirm/apps/usrp_rx/views.py +++ b/volumes/sirm/apps/usrp_rx/views.py @@ -12,6 +12,16 @@ from apps.main.views import sidebar from .models import USRPRXConfiguration from .forms import USRPRXConfigurationForm, USRPRXImportForm +def is_developer(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Developer' in groups or user.is_staff + return 'Developer' in groups or user.is_superuser + + +def is_operator(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Operator' in groups or user.is_staff + return 'Operator' in groups or user.is_superuser def conf(request, conf_id): @@ -38,12 +48,14 @@ def conf_edit(request, conf_id): conf = get_object_or_404(USRPRXConfiguration, pk=conf_id) + if not is_developer(request.user): + messages.error(request, 'You must be an developer to edit this configuration') + return redirect(conf.get_absolute_url()) + if request.method=='GET': - form = USRPRXConfigurationForm(instance=conf) elif request.method=='POST': - line_data = {} conf_data = {} clock_data = {} diff --git a/volumes/sirm/apps/usrp_tx/views.py b/volumes/sirm/apps/usrp_tx/views.py index e4d5157..6f275b7 100644 --- a/volumes/sirm/apps/usrp_tx/views.py +++ b/volumes/sirm/apps/usrp_tx/views.py @@ -13,6 +13,17 @@ from .models import USRPTXConfiguration, TXCode from .forms import USRPTXConfigurationForm, USRPTXImportForm from .validations import validation_usrp_tx_code +def is_developer(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Developer' in groups or user.is_staff + return 'Developer' in groups or user.is_superuser + + +def is_operator(user): + groups = [str(g.name) for g in user.groups.all()] + #return 'Operator' in groups or user.is_staff + return 'Operator' in groups or user.is_superuser + def conf(request, conf_id): @@ -44,6 +55,10 @@ def conf_edit(request, conf_id): conf = get_object_or_404(USRPTXConfiguration, pk=conf_id) + if not is_developer(request.user): + messages.error(request, 'You must be an developer to edit this configuration') + return redirect(conf.get_absolute_url()) + if request.method=='GET': form = USRPTXConfigurationForm(instance=conf)