...
 
Commits (34)
......@@ -11,3 +11,7 @@ ALTER "id" SET NOT NULL;
SELECT setval('core_tag_id_seq', (SELECT MAX(id) FROM core_tag)+1);
delete from multiplicity_graphtype where id = 1;
UPDATE staf_material SET parent_id = 970921 WHERE id = 971057;
SELECT setval('core_organization_id_seq', (SELECT MAX(id) FROM core_organization)+1);
# Generated by Django 2.1.3 on 2018-12-11 06:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('staf', '0011_auto_20181208_0714'),
('core', '0021_auto_20181125_0602'),
]
operations = [
migrations.AddField(
model_name='reference',
name='processes',
field=models.ManyToManyField(blank=True, limit_choices_to={'slug__isnull': False}, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-11 06:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0022_reference_processes'),
]
operations = [
migrations.AlterField(
model_name='reference',
name='date_added',
field=models.DateTimeField(auto_now_add=True, null=True),
),
]
# Generated by Django 2.1.3 on 2018-12-11 06:19
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('multiplicity', '0028_information_photo'),
('core', '0023_auto_20181211_0617'),
]
operations = [
migrations.AddField(
model_name='reference',
name='primary_space',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='multiplicity.ReferenceSpace'),
),
]
# Generated by Django 2.1.3 on 2018-12-11 06:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0024_reference_primary_space'),
]
operations = [
migrations.AddField(
model_name='reference',
name='file',
field=models.FileField(blank=True, null=True, upload_to='references'),
),
]
# Generated by Django 2.1.3 on 2018-12-11 09:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('staf', '0011_auto_20181208_0714'),
('multiplicity', '0028_information_photo'),
('core', '0025_reference_file'),
]
operations = [
migrations.RemoveField(
model_name='organization',
name='location',
),
migrations.AddField(
model_name='organization',
name='processes',
field=models.ManyToManyField(blank=True, limit_choices_to={'slug__isnull': False}, to='staf.Process'),
),
migrations.AddField(
model_name='organization',
name='reference_spaces',
field=models.ManyToManyField(blank=True, to='multiplicity.ReferenceSpace'),
),
]
......@@ -39,7 +39,8 @@ class ReferenceType(models.Model):
class Organization(models.Model):
name = models.CharField(max_length=255)
url = models.CharField(max_length=255, null=True, blank=True)
location = models.ForeignKey(ReferenceSpace, on_delete=models.SET_NULL, null=True, blank=True)
processes = models.ManyToManyField('staf.Process', blank=True, limit_choices_to={'slug__isnull': False})
reference_spaces = models.ManyToManyField(ReferenceSpace, blank=True)
description = models.TextField(null=True, blank=True)
parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)
ORG_TYPE = (
......@@ -61,6 +62,11 @@ class Organization(models.Model):
class Meta:
ordering = ["name"]
class OrganizationForm(ModelForm):
class Meta:
model = Organization
exclude = ['id', 'processes']
class Publisher(models.Model):
name = models.CharField(max_length=255)
......@@ -258,7 +264,8 @@ class Reference(models.Model):
year = models.PositiveSmallIntegerField()
abstract = models.TextField(null=True, blank=True)
abstract_original_language = models.TextField(null=True, blank=True)
date_added = models.DateTimeField(null=True, blank=True)
date_added = models.DateTimeField(null=True, blank=True, auto_now_add=True)
file = models.FileField(null=True, blank=True, upload_to='references')
LANGUAGES = (
('EN', 'English'),
('ES', 'Spanish'),
......@@ -281,6 +288,8 @@ class Reference(models.Model):
authors = models.ManyToManyField(People, blank=True)
organizations = models.ManyToManyField(Organization, through='ReferenceOrganization')
tags = models.ManyToManyField(Tag, blank=True, limit_choices_to={'hidden': False})
processes = models.ManyToManyField('staf.Process', blank=True, limit_choices_to={'slug__isnull': False})
primary_space = models.ForeignKey(ReferenceSpace, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.title
......@@ -307,7 +316,7 @@ class ReferenceForm(ModelForm):
class ReferenceFormAdmin(ModelForm):
class Meta:
model = Reference
exclude = ['id', 'organizations']
exclude = ['id', 'organizations', 'processes', 'date_added']
labels = {
'authorlist': 'Author(s)',
'doi': 'DOI',
......
......@@ -97,6 +97,11 @@ urlpatterns = [
path('admin/publications/<int:id>/tags', views.admin_referencetags, name='admin_referencetags'),
path('admin/publications', views.admin_references, name='admin_references'),
path('admin/organizations', views.admin_organization_list, name='admin_organization_list'),
path('admin/organizations/<int:id>', views.admin_organization, name='admin_organization'),
path('admin/organizations/create', views.admin_organization, name='admin_organization'),
path('admin/organizations/create/<slug:slug>', views.admin_organization, name='admin_organization_referencespace'),
#temp
path('updateorgs', views.updateorgs),
]
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from .models import Video, Journal, Organization, Publisher, Reference, ReferenceForm, ReferenceFormAdmin, People, Article, PeopleForm, Video, VideoForm, ReferenceOrganization, Project, UserAction, UserLog, SimpleArticleForm, ProjectForm, EventForm, ReferenceType, Tag, Event, TagForm
from .models import Video, Journal, Organization, Publisher, Reference, ReferenceForm, ReferenceFormAdmin, People, Article, PeopleForm, Video, VideoForm, ReferenceOrganization, Project, UserAction, UserLog, SimpleArticleForm, ProjectForm, EventForm, ReferenceType, Tag, Event, TagForm, OrganizationForm
from team.models import Category, TaskForceMember, TaskForceTicket, TaskForceUnit
from multiplicity.models import ReferenceSpace
from staf.models import Data
from staf.models import Data, Process
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from django.db.models import Count
......@@ -226,6 +226,8 @@ def reference(request, id):
@login_required
def referenceform(request, id=False, dataset=False):
processes = Process.objects.filter(slug__isnull=False).order_by('id')
new_record = False
if id:
info = get_object_or_404(Reference, pk=id)
if request.user.is_staff:
......@@ -235,30 +237,39 @@ def referenceform(request, id=False, dataset=False):
else:
info = False
if request.user.is_staff:
form = ReferenceFormAdmin()
form = ReferenceFormAdmin(initial={'language': 'EN', 'status': 'active'})
else:
form = ReferenceForm()
if request.method == 'POST':
if not id:
new_record = True
if request.user.is_staff:
form = ReferenceFormAdmin(request.POST)
form = ReferenceFormAdmin(request.POST, request.FILES)
else:
form = ReferenceForm(request.POST)
else:
if request.user.is_staff:
form = ReferenceFormAdmin(request.POST, instance=info)
form = ReferenceFormAdmin(request.POST, request.FILES, instance=info)
else:
form = ReferenceForm(request.POST, instance=info)
if form.is_valid():
info = form.save()
create_record = get_object_or_404(UserAction, pk=1)
log = UserLog(user=request.user, action=create_record, reference=info, points=5)
if new_record:
create_record = get_object_or_404(UserAction, pk=1)
log = UserLog(user=request.user, action=create_record, reference=info, points=5)
else:
info.processes.clear()
selected = request.POST.getlist('process')
for process in selected:
info.processes.add(Process.objects.get(pk=process))
messages.success(request, 'Information was saved.')
return redirect('core:reference', id=info.id)
else:
messages.error(request, 'We could not save your form, please correct the errors')
context = { 'section': 'resources', 'page': 'publications', 'info': info, 'form': form, 'dataset': dataset}
context = { 'section': 'resources', 'page': 'publications', 'info': info, 'form': form, 'dataset': dataset, 'processes': processes }
return render(request, 'core/reference.form.html', context)
def references(request, type=False, tag=False):
......@@ -662,6 +673,46 @@ def admin_video(request, id=False):
return render(request, 'core/admin/video.html', context)
@staff_member_required
def admin_organization_list(request):
list = Organization.on_site.all()
context = { 'navbar': 'backend', 'list': list, 'datatables': True }
return render(request, 'core/admin/organizations.list.html', context)
@staff_member_required
def admin_organization(request, id=False, slug=False):
space = False
if slug:
space = get_object_or_404(ReferenceSpace, slug=slug)
if id:
info = get_object_or_404(Organization, pk=id)
form = OrganizationForm(instance=info)
else:
info = False
form = OrganizationForm()
if request.method == 'POST':
if not id:
form = OrganizationForm(request.POST, request.FILES)
else:
form = OrganizationForm(request.POST, request.FILES, instance=info)
if form.is_valid():
info = form.save()
if id:
info.processes.clear()
selected = request.POST.getlist('process')
for process in selected:
info.processes.add(Process.objects.get(pk=process))
messages.success(request, 'Information was saved.')
return redirect(reverse('core:admin_organization', args=[info.id]))
else:
messages.error(request, 'We could not save your form, please correct the errors')
processes = Process.objects.filter(slug__isnull=False).order_by('id')
context = { 'navbar': 'backend', 'form': form, 'info': info, 'select2': True, 'space': space, 'processes': processes }
return render(request, 'core/admin/organization.html', context)
@staff_member_required
def admin_article(request, id=False, type=False, parent=False):
eventform = False
......
......@@ -167,7 +167,7 @@ LOGGING = {
TINYMCE_DEFAULT_CONFIG = {
'height': 360,
'width': 1120,
'width': 980,
'cleanup_on_startup': True,
'custom_undo_redo_levels': 20,
'selector': 'textarea',
......
from django.contrib import admin
from .models import Topic, DatasetType, ReferenceSpace, ReferenceSpaceType, ReferenceSpaceLocation, ReferenceSpaceFeature, Feature, ReferenceSpaceTypeDescription, DQIRating, DQI, Information, ReferenceSpaceCSV, GraphType, DatasetTypeStructure, Photo, ProcessGroup
from .models import Topic, DatasetType, ReferenceSpace, ReferenceSpaceType, ReferenceSpaceLocation, ReferenceSpaceFeature, Feature, ReferenceSpaceTypeDescription, DQIRating, DQI, Information, ReferenceSpaceCSV, GraphType, DatasetTypeStructure, Photo, ProcessGroup, License
class ReferenceSpaceTypeAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("name",)}
......@@ -23,3 +23,4 @@ admin.site.register(GraphType)
admin.site.register(DatasetTypeStructure)
admin.site.register(Photo)
admin.site.register(ProcessGroup)
admin.site.register(License)
from django.contrib.sites.models import Site
from core.models import Event
from multiplicity.models import ProcessGroup
from datetime import datetime, timedelta, time
def site(request):
site = Site.objects.get_current()
today = datetime.now().date()
event = Event.objects.filter(article__site=site, start__gte=today).order_by('start').first()
processgroups = ProcessGroup.objects.order_by('name').exclude(pk__in=[13,14,12])
return {'SITE_ID': site.id, 'SITE_URL': site.domain, 'SITE_NAME': site.name, 'EVENT': event}
return {'SITE_ID': site.id, 'SITE_URL': site.domain, 'SITE_NAME': site.name, 'EVENT': event, 'PROCESSGROUPS': processgroups}
# Generated by Django 2.1.3 on 2018-12-07 15:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('multiplicity', '0020_processgroup'),
]
operations = [
migrations.AddField(
model_name='information',
name='processgroup',
field=models.ManyToManyField(blank=True, to='multiplicity.ProcessGroup'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 05:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('multiplicity', '0021_information_processgroup'),
]
operations = [
migrations.AlterField(
model_name='information',
name='processes',
field=models.ManyToManyField(blank=True, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 06:46
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('staf', '0009_dataset_process'),
('multiplicity', '0022_auto_20181208_0545'),
]
operations = [
migrations.AddField(
model_name='referencespacetype',
name='process',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 07:04
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('staf', '0010_process_slug'),
('multiplicity', '0023_referencespacetype_process'),
]
operations = [
migrations.RemoveField(
model_name='photo',
name='topic',
),
migrations.AddField(
model_name='photo',
name='process',
field=models.ForeignKey(blank=True, limit_choices_to={'slug__isnull': False}, null=True, on_delete=django.db.models.deletion.CASCADE, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 07:19
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('staf', '0011_auto_20181208_0714'),
('multiplicity', '0024_auto_20181208_0704'),
]
operations = [
migrations.RemoveField(
model_name='information',
name='processes',
),
migrations.RemoveField(
model_name='information',
name='processgroup',
),
migrations.RemoveField(
model_name='information',
name='topic',
),
migrations.RemoveField(
model_name='information',
name='type',
),
migrations.AddField(
model_name='information',
name='process',
field=models.ForeignKey(blank=True, limit_choices_to={'slug__isnull': False}, null=True, on_delete=django.db.models.deletion.CASCADE, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 07:40
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('multiplicity', '0025_auto_20181208_0719'),
]
operations = [
migrations.AlterField(
model_name='referencespacetype',
name='process',
field=models.ForeignKey(blank=True, limit_choices_to={'slug__isnull': False}, null=True, on_delete=django.db.models.deletion.CASCADE, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 07:55
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('multiplicity', '0026_auto_20181208_0740'),
]
operations = [
migrations.CreateModel(
name='License',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('url', models.CharField(blank=True, max_length=255, null=True)),
],
),
migrations.AddField(
model_name='photo',
name='license',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='multiplicity.License'),
),
]
# Generated by Django 2.1.3 on 2018-12-11 04:49
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('multiplicity', '0027_auto_20181208_0755'),
]
operations = [
migrations.AddField(
model_name='information',
name='photo',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='multiplicity.Photo'),
),
]
......@@ -7,6 +7,7 @@ from django.forms import ModelForm
# Used for image resizing
from stdimage.models import StdImageField
import re
User = get_user_model()
......@@ -44,6 +45,7 @@ class ReferenceSpaceType(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(db_index=True, max_length=255, unique=True)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, null=True, blank=True)
process = models.ForeignKey('staf.Process', on_delete=models.CASCADE, null=True, blank=True, limit_choices_to={'slug__isnull': False})
SPACE_TYPE = (
('SOC', 'Socio-economic System'),
('NAT', 'Natural Environment'),
......@@ -212,23 +214,64 @@ class DQIRating(models.Model):
class Meta:
ordering = ["score"]
class ProcessGroup(models.Model):
name = models.CharField(max_length=255)
icon = models.CharField(max_length=255, null=True, blank=True)
slug = models.SlugField(db_index=True, max_length=255, unique=True)
description = models.TextField(null=True, blank=True)
processes = models.ManyToManyField('staf.Process', blank=True)
def __str__(self):
return self.name
class License(models.Model):
name = models.CharField(max_length=255)
url = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return self.name
class Photo(TimestampedModel):
image = StdImageField(upload_to='photos', variations={'thumbnail': (200, 150), 'large': (1024, 780),})
author = models.CharField(max_length=255)
source_url = models.CharField(max_length=255, null=True, blank=True)
process = models.ForeignKey('staf.Process', on_delete=models.CASCADE, null=True, blank=True, limit_choices_to={'slug__isnull': False})
description = models.TextField(null=True, blank=True)
primary_space = models.ForeignKey(ReferenceSpace, on_delete=models.CASCADE)
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE)
deleted = models.BooleanField(default=False, db_index=True)
license = models.ForeignKey(License, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
if self.description:
cleanr = re.compile('<.*?>')
description = re.sub(cleanr, '', self.description)
description = description[:30] + " - " + self.author + " - #" + str(self.id)
else:
description = "Photo by " + self.author + " - #" + str(self.id)
return description
class PhotoForm(ModelForm):
class Meta:
model = Photo
exclude = ['id', 'uploaded_by', 'primary_space', 'deleted', 'process']
class Information(TimestampedModel):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=255)
content = HTMLField('Content')
space = models.ForeignKey(ReferenceSpace, on_delete=models.CASCADE)
photo = models.ForeignKey(Photo, on_delete=models.CASCADE, null=True, blank=True)
references = models.ManyToManyField("core.Reference", blank=True)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, blank=True, null=True)
dataset_types = models.ManyToManyField(DatasetType, blank=True, limit_choices_to={'active': True})
type = models.ForeignKey(ReferenceSpaceType, on_delete=models.CASCADE, null=True, blank=True)
processes = models.ManyToManyField("staf.Process", blank=True, limit_choices_to={'is_separator': False})
process = models.ForeignKey("staf.Process", on_delete=models.CASCADE, blank=True, null=True, limit_choices_to={'slug__isnull': False})
def __str__(self):
return self.title
class InformationForm(ModelForm):
class Meta:
model = Information
fields = ['title', 'content', 'dataset_types']
fields = ['title', 'content', 'photo']
class GraphType(models.Model):
title = models.CharField(max_length=255)
......@@ -251,30 +294,3 @@ class GraphType(models.Model):
def __str__(self):
return self.title
class Photo(TimestampedModel):
image = StdImageField(upload_to='photos', variations={'thumbnail': (200, 150), 'large': (1024, 780),})
author = models.CharField(max_length=255)
source_url = models.CharField(max_length=255, null=True, blank=True)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, null=True, blank=True, limit_choices_to={'parent__isnull': True})
description = models.TextField(null=True, blank=True)
primary_space = models.ForeignKey(ReferenceSpace, on_delete=models.CASCADE)
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE)
deleted = models.BooleanField(default=False, db_index=True)
def __str__(self):
return self.author or 'No name'
class PhotoForm(ModelForm):
class Meta:
model = Photo
exclude = ['id', 'uploaded_by', 'primary_space', 'deleted']
class ProcessGroup(models.Model):
name = models.CharField(max_length=255)
icon = models.CharField(max_length=255, null=True, blank=True)
slug = models.SlugField(db_index=True, max_length=255, unique=True)
description = models.TextField(null=True, blank=True)
processes = models.ManyToManyField('staf.Process', blank=True)
def __str__(self):
return self.name
This diff is collapsed.
/* This is the right file! */
.main-content-block a:not(.btn){color:#0391d1}
.main-content-block a.not(.btn):hover{text-decoration:underline}
.main-content-block .panel-colorful:not(.panel-default) a:not(.btn){color:#fff}
.main-content-block .chat-me a{
color: #fff;
font-weight: bold;
text-decoration: underline;
}
#navbar .brand-title {
padding:0;
text-align:center;
}
.chat-body .chat-me .media-body {
text-align:left;
}
.chat-body .chat-me .media-left {
float:left;
padding: 0 10px 0 0;
}
.chat-user-list > a.clicked {
background:#ECF0F5;
}
#container.boxed-layout {
background:#fff;
}
#page-content{background:#fff}
#page-content a:not(.btn):not(.list-group-item):hover{text-decoration:underline}
#page-content .nav-tabs.nav-tabs-inverted a:hover,#page-content .leaflet-container a:hover,#page-content .nav a:hover{text-decoration:none}
.bluemarker {
background:url('../../multiplicity/img/markers/marker.blue.png');
}
.redmarker {
background:url('../../multiplicity/img/markers/marker.red.png');
}
.greenmarker {
background:url('../../multiplicity/img/markers/marker.green.png');
}
.darkbluemarker {
background:url('../../multiplicity/img/markers/marker.darkblue.png');
}
.purplemarker {
background:url('../../multiplicity/img/markers/marker.purple.png');
}
.yellowmarker {
background:url('../../multiplicity/img/markers/marker.yellow.png');
}
.top-page-tabs.nav-tabs li{background:#ecf0f5;opacity:0.67;margin-right:2px}
.top-page-tabs.nav-tabs li.active{opacity:1}
body{font-size:15px;line-height:1.5}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6, #page-title{color:#333}
.main-content-block .references a span{display:block;color:#333}
.main-content-block .alert-info a:not(.btn){color:#fff;text-decoration:underline}
.fa-plus-square.fa-lg{margin-right:6px}
.label-text {
margin-top:7px;
}
.leaflet-popup-content img{padding:4px;border:1px solid #ccc;margin-bottom:10px;max-width:100%}
.leaflet-popup-content{text-align:center}
.legend img{position:relative;top:6px}
#editpagebutton,#controlpanelbutton, #addpagebutton, #datasetbutton, #deletepagebutton, #editextrabutton {
display: inline-block;
background-color: #3a444e;
border-radius: 7px 0 0 7px !important;
color: #fff;
border: 0;
position: fixed;
top: 250px;
right:0;
margin-left: -1%;
border-radius: 2px 0 0 2px;
box-shadow: none;
z-index: 1;
transition: all .3s;
}
#editpagebutton {
top:200px;
}
#addpagebutton {
top:300px;
}
#editextrabutton {
top:400px;
}
#datasetbutton {
top:350px;
}
#deletepagebutton {
top:auto;
bottom:20px;
opacity:0.4;
}
#deletepagebutton:hover {
opacity:1;
background-color:red;
}
#editpagebutton i,#controlpanelbutton i,#addpagebutton i, #datasetbutton i, #deletepagebutton i, #editextrabutton i{
font-size: 25px;
display: block;
margin: 5px 0;
height: 1em;
animation-iteration-count: infinite !important;
animation-duration: 1.5s !important;
animation-play-state: running;
}
.panel-default.panel-colorful {
background:#fff;
}
.panel .well, .panel pre,.boxit .well, .boxit pre {
background:#fff;
}
#container.aside-bright #aside #topiclist a.underline {
color:#000;
text-decoration:underline;
}
#container.aside-bright #aside #topiclist a.underline:hover {
text-decoration:none;
}
#navbar h4 i.psi-lock{font-size:22px;margin-right:5px}
.nav-tabs.nav-tabs-inverted > li.active > a, .nav-tabs.nav-tabs-inverted > li.active > a:focus, .nav-tabs.nav-tabs-inverted > li.active > a:hover
{
background-color: #ecf0f5;
border: 2px solid rgba(0,0,0,0.07);
border-bottom-color: transparent;
}
.panel.padding10{padding:10px}
/* This is the reverse floating style for some pages */
.floating-style .nav-tabs > li.active > a, .floating-style .nav-tabs > li.active > a:focus, .floating-style .nav-tabs > li.active > a:hover
{
background-color: #ecf0f5;
border-bottom-color: transparent;
font-weight:bold;
}
.floating-style .nav-tabs {
border:none;
}
.floating-style .top-page-tabs.nav-tabs li {
background:none;
}
.floating-style #content-container {
background:#fff;
}
.floating-style .panel:not(.panel-colorful) {
background-color: #ecf0f5;
}
.floating-style .top-page-tabs a:not(.btn) {
color: #232424;
}
.boxit {
background:#ecf0f5;
}
/* Making floating style the default */
.nav-tabs > li.active > a, .nav-tabs > li.active > a:focus, .nav-tabs > li.active > a:hover
{
background-color: #ecf0f5;
border-bottom-color: transparent;
font-weight:bold;
}
.nav-tabs {
border:none;
}
.top-page-tabs.nav-tabs li {
background:none;
}
#content-container {
background:#fff;
}
.panel:not(.panel-colorful) {
background-color: #ecf0f5;
}
.top-page-tabs a:not(.btn) {
color: #232424;
}
/* Play around with fonts */
@import url('https://fonts.googleapis.com/css?family=Lato|Roboto');
body, .leaflet-container {
font-family: 'Lato', sans-serif;
}
h1,h2,h3,h4,h5,h6,.brand-text{
font-family: 'Roboto', sans-serif;
}
.brand-text{
font-weight:400;
}
#container .table th,body, #content-container {
color:#000;
}
#container .badge {
font-weight:400;
}
footer#footer, footer#actions {
position:static;
background:#000;
color:#fff;
opacity:0.85;
padding-top:4vh;
padding-bottom:4vh;
height:auto;
}
footer#footer img {
width:120px;
margin: 0 auto;
display:block;
}
#footer h4 {
color:#ccc;
}
#footer .nav > li > a {
padding:3px;
}
#footer .nav > li > a:focus, #footer .nav > li > a:hover {
background:none;
text-decoration:underline;
color:#fff;
}
footer#actions{
background:#ECF0F5;
color:#333;
font-size:2rem;
}
@media (max-width:992px){
.brand-title{width:0}
}
@media (max-width:750px){
#topstrip .rightbox {left:130px}
#topstrip .leftbox{width:120px}
}
@media (max-width:520px){
.navbar-top-links i{display:none}
#topstrip .leftbox{width:1px;overflow:hidden}
#topstrip .rightbox{left:0}
}
@media (max-width:420px){
li[data-id="services"]{display:none}
}
.navbar-content {
text-align:left;
}
body .select2-container--default .select2-selection--multiple .select2-selection__choice {
border-color: #bebebe;
}
body .select2-container--default .select2-results__option[aria-selected="true"]:hover, body .select2-container--default .select2-selection--multiple .select2-selection__choice, body .select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #8a8684;
}
/* Temporary increasing size for video
body{font-size:18px;line-height:1.5}
#container.boxed-layout .boxed, #container.boxed-layout #footer{max-width:1500px;width:1600px}
#topstrip .leftbox{position:relative;right:186px}
.btn,.navbar-content li.dropdown > a{font-size:18px}
h5{font-size:18px}
.blog h2{font-size:20px}
#topstrip .leftbox{right:125px}
*/
......@@ -47,6 +47,7 @@ urlpatterns = [
path('<slug:city>/information/<int:id>', views.information_form, name='information_form'),
path('<slug:city>/photo', views.photo_form, name='photo_form'),
path('<slug:city>/photo/<int:id>', views.photo_form, name='photo_form'),
path('<slug:city>/sectors/<slug:sector>', views.sector, name='sector'),
# Uploading data
path('<slug:city>/upload', views.upload, name='upload'),
......
......@@ -92,6 +92,22 @@ def map(request, city, type='boundaries'):
context = { 'section': 'cities', 'menu': 'maps', 'page': type, 'info': info, 'topics': topics }
return render(request, 'multiplicity/space.map.html', context)
def sector(request, city, sector):
info = get_object_or_404(ReferenceSpace, slug=city)
sector = get_object_or_404(ProcessGroup, slug=sector)
information = Information.objects.filter(process__in=sector.processes.all(), space=info)
datasets = Dataset.objects.filter(process__in=sector.processes.all())
spaces = ReferenceSpace.objects.filter(city=info, type__process__in=sector.processes.all())
addlink = reverse('multiplicity:information_form', args=[info.slug])
map = False
types = ReferenceSpaceType.objects.filter(process__in=sector.processes.all()).annotate(total=Count('referencespace', filter=Q(referencespace__city=info)))
if spaces:
map = True
context = { 'section': 'cities', 'menu': 'sectors', 'sector': sector, 'info': info, 'information': information, 'datasets': datasets, 'spaces': spaces, 'map': map,
'addlink': addlink, 'types': types,
}
return render(request, 'multiplicity/sector.html', context)
def overview(request, city, slug):
groups = ProcessGroup.objects.order_by('name')
flow = get_object_or_404(DatasetTypeStructure, slug=slug)
......@@ -310,13 +326,22 @@ def upload_infrastructure_file(request, city, type):
features = Feature.objects.filter(type=type.id)
previous = ReferenceSpaceCSV.objects.filter(user=request.user, type=type, space=info)
if request.method == 'POST':
file = request.FILES['file']
filename = str(uuid.uuid4())
path = settings.MEDIA_ROOT + '/csv-referencespace/' + filename
if 'data' in request.POST:
input = request.POST['data']
filename = str(uuid.uuid4())
file = 'Data entry on ' + datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
path = settings.MEDIA_ROOT + '/csv-referencespace/' + filename
in_txt = csv.reader(input.split('\n'), delimiter = '\t')
out_csv = csv.writer(open(path, 'w', newline=''))
out_csv.writerows(in_txt)
else:
file = request.FILES['file']
filename = str(uuid.uuid4())
path = settings.MEDIA_ROOT + '/csv-referencespace/' + filename
with open(path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
with open(path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
csv_file = ReferenceSpaceCSV(name=filename, original_name=file, imported=False, user=request.user, type=type, space=info)
csv_file.save()
......@@ -1048,7 +1073,8 @@ def materials(request):
@login_required
def information_form(request, city, id=False, topic=False):
info = get_object_or_404(ReferenceSpace, slug=city)
processes = Process.objects.filter(parent=398480).order_by('id')
processes = Process.objects.filter(slug__isnull=False).order_by('id')
references = Reference.objects.filter(status='active')
if id:
information = get_object_or_404(Information, pk=id)
form = InformationForm(instance=information)
......@@ -1062,20 +1088,27 @@ def information_form(request, city, id=False, topic=False):
else:
form = InformationForm(request.POST, request.FILES, instance=information)
if form.is_valid():
if request.POST['process']:
process = Process.objects.get(pk=request.POST['process'])
else:
process = None
if id:
information = form.save()
information.process = process
information.save()
else:
information = form.save(commit=False)
information.process = process
information.space = info
information.user = request.user
information.save()
form.save_m2m()
information.processes.clear()
information.references.clear()
selected = request.POST.getlist('processes')
for process in selected:
information.processes.add(Process.objects.get(pk=process))
selected = request.POST.getlist('references')
for reference in selected:
information.references.add(Reference.objects.get(pk=reference))
saved = True
messages.success(request, 'Information was saved.')
......@@ -1083,15 +1116,18 @@ def information_form(request, city, id=False, topic=False):
else:
messages.warning(request, 'We could not save your form, please correct the errors')
context = { 'section': 'cities', 'info': info, 'form': form, 'type': type, 'tinymce': True, 'processes': processes, 'information': information }
context = { 'section': 'cities', 'info': info, 'form': form, 'type': type, 'tinymce': True, 'processes': processes, 'information': information,
'references': references, 'select2': True
}
return render(request, 'multiplicity/form.information.html', context)
@login_required
def photo_form(request, city, id=False):
info = get_object_or_404(ReferenceSpace, slug=city)
processes = Process.objects.filter(slug__isnull=False).order_by('id')
if id:
photo = get_object_or_404(Photo, pk=id)
form = PhotoForm(instance=info)
form = PhotoForm(instance=photo)
else:
photo = False
form = PhotoForm()
......@@ -1102,9 +1138,14 @@ def photo_form(request, city, id=False):
else:
form = PhotoForm(request.POST, request.FILES, instance=photo)
if form.is_valid():
if request.POST['process']:
process = Process.objects.get(pk=request.POST['process'])
else:
process = None
photo = form.save(commit=False)
photo.primary_space = info
photo.uploaded_by = request.user
photo.process = process
photo.save()
saved = True
messages.success(request, 'Photo was saved.')
......@@ -1112,7 +1153,7 @@ def photo_form(request, city, id=False):
else:
messages.warning(request, 'We could not save your form, please correct the errors')
context = { 'section': 'cities', 'info': info, 'form': form, 'type': type }
context = { 'section': 'cities', 'info': info, 'form': form, 'type': type, 'processes': processes, 'photo': photo }
return render(request, 'multiplicity/form.photo.html', context)
......@@ -1203,7 +1244,11 @@ def admin_data_overview(request, city):
datasets = Dataset.objects.filter(primary_space=info, deleted=False)
csv = CSV.objects.filter(space=info)
space_csv = ReferenceSpaceCSV.objects.filter(space=info)
context = { 'navbar': 'backend', 'info': info, 'datasets': datasets, 'csv': csv, 'space_csv': space_csv, 'datatables': True }
spaces = ReferenceSpace.objects.filter(city=info)
photos = Photo.objects.filter(primary_space=info)
information = Information.objects.filter(space=info)
context = { 'navbar': 'backend', 'info': info, 'datasets': datasets, 'csv': csv, 'space_csv': space_csv, 'datatables': True,
'information': information, 'spaces': spaces, 'photos': photos }
return render(request, 'multiplicity/admin/overview.data.html', context)
@staff_member_required
......
# Generated by Django 2.1.3 on 2018-12-07 15:25
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('staf', '0007_process_code'),
]
operations = [
migrations.AlterModelOptions(
name='process',
options={'ordering': ['id']},
),
]
# Generated by Django 2.1.3 on 2018-12-08 05:56
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('staf', '0008_auto_20181207_1525'),
]
operations = [
migrations.AddField(
model_name='dataset',
name='process',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='staf.Process'),
),
]
# Generated by Django 2.1.3 on 2018-12-08 07:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('staf', '0009_dataset_process'),
]
operations = [
migrations.AddField(
model_name='process',
name='slug',
field=models.SlugField(blank=True, max_length=255, null=True),
),
]
# Generated by Django 2.1.3 on 2018-12-08 07:14
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('staf', '0010_process_slug'),
]
operations = [
migrations.AlterField(
model_name='dataset',
name='process',
field=models.ForeignKey(blank=True, limit_choices_to={'slug__isnull': False}, null=True, on_delete=django.db.models.deletion.CASCADE, to='staf.Process'),
),
]
......@@ -20,6 +20,7 @@ class Process(models.Model):
name = models.CharField(max_length=255, db_index=True)
code = models.CharField(max_length=255, null=True, blank=True, db_index=True)
description = models.TextField(null=True, blank=True)
slug = models.SlugField(db_index=True, max_length=255, null=True, blank=True)
type = models.ForeignKey(ProcessType, on_delete=models.CASCADE, null=True, blank=True)
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
is_separator = models.BooleanField()
......@@ -103,6 +104,7 @@ class Dataset(models.Model):
type = models.ForeignKey('multiplicity.DatasetType', on_delete=models.CASCADE, null=True, blank=True)
graph = models.ForeignKey('multiplicity.GraphType', on_delete=models.CASCADE, null=True, blank=True)
topics = models.ManyToManyField(Topic, blank=True)
process = models.ForeignKey(Process, on_delete=models.CASCADE, null=True, blank=True, limit_choices_to={'slug__isnull': False})
deleted = models.BooleanField(default=False, db_index=True)
def __str__(self):
return self.name
......
......@@ -6,7 +6,8 @@ app_name = 'staf'
urlpatterns = [
path('', views.index, name='index'),
path('search', views.search, name='search'),
path('catalogs', views.catalogs, name='catalogs'),
path('processgroups', views.processgroups, name='processgroups'),
path('processgroups/<int:id>', views.processgroup, name='processgroup'),
path('materials', views.materiallist, name='materials'),
path('materials/<int:id>', views.materiallist, name='materiallist'),
......@@ -16,6 +17,7 @@ urlpatterns = [
path('materials/ajax', views.materiallistajax, name='materialajax'),
path('processes', views.processlist, name='processes'),
path('processes/table', views.processtable, name='processtable'),
path('processes/<int:id>', views.processlist, name='processlist'),
path('processes/<int:id>/edit', views.processform, name='process_edit'),
path('processes/<int:id>/child', views.processchild, name='process_child'),
......
......@@ -3,7 +3,7 @@ from django.shortcuts import render, get_object_or_404, redirect
from .models import Material, Process, Unit, Dataset, DatasetForm, CSV, MaterialForm, ProcessForm, Data
from core.models import Reference
from multiplicity.models import ReferenceSpace, DatasetType
from multiplicity.models import ReferenceSpace, DatasetType, ProcessGroup
from django.contrib.auth.decorators import login_required
# For file uploads
......@@ -26,12 +26,16 @@ def search(request):
return render(request, 'staf/search.html', context)
@login_required
def catalogs(request):
materials = Material.objects.filter(parent__isnull=True)
processes = Process.objects.filter(parent__isnull=True)
datasets = Dataset.objects.all()
context = { 'section': 'tools', 'menu': 'staf', 'materials': materials, 'processes': processes, 'datasets': datasets }
return render(request, 'staf/index.html', context)
def processgroups(request):
list = ProcessGroup.objects.order_by('name')
context = { 'list': list, 'datatables': True }