diff --git a/requirements.txt b/requirements.txt index 45f19cb9f78777ca12ff7823d277c0e1f7247d95..07ec22f5054418e35a194c1cb29e9b3c55a9d2f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -58,4 +58,4 @@ timeout-decorator==0.4.0 Unidecode==1.0.22 urllib3==1.23 xlrd==1.1.0 -xlwt==1.3.0 +xlwt==1.3.0 \ No newline at end of file diff --git a/smash/import_file.py b/smash/import_file.py index 672f8a41f496e73eebf155dc66f2a18186dd3383..e5bdda7a871f804e0e02ce1f43e45ff36b27be85 100644 --- a/smash/import_file.py +++ b/smash/import_file.py @@ -363,7 +363,9 @@ def create_appointment_types(assessments): def create_languages(languages_cell): languages = [] - for language in languages_cell: + if not os.path.isdir(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + for language in row['LANGUAGES']: lang, created = Language.objects.get_or_create( name=language, locale=locale_table.get(language,(None, None))[0]) if created: @@ -376,6 +378,7 @@ def create_languages(languages_cell): language_flags[language]) basename = os.path.basename(src) dst = os.path.join(MEDIA_ROOT, basename) + logging.warn('Copying file {} to {}'.format(src, dst)) copyfile(src, dst) # .save(basename, File(open(dst, 'rb'))) #SimpleUploadedFile(name=path, content=open(path, 'rb').read(), content_type='image/png') lang.image = basename diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py index 65c16192eaa3d4da0e31894a856424fe8c1a1680..6e27ce37779b10ea44f2e4d5894e5766d9496848 100644 --- a/smash/web/api_views/subject.py +++ b/smash/web/api_views/subject.py @@ -1,5 +1,6 @@ import logging +from django.urls import reverse from django.db.models import Count, Case, When, Min, Max from django.db.models import Q from django.http import JsonResponse @@ -325,7 +326,6 @@ def types(request): "types": data }) - def serialize_subject(study_subject): location = location_to_str(study_subject.default_location) flying_team = flying_team_to_str(study_subject.flying_team) @@ -356,10 +356,19 @@ def serialize_subject(study_subject): status = "SHOULD_BE_IN_PROGRESS" else: status = "UPCOMING" + + appointment_types = ['{} ({})'.format(at.code, at.description) for at in visit.appointment_types.all()] + if len(appointment_types) == 0: + appointment_types = ['No appointment types set.'] + serialized_visits.append({ "status": status, + "appointment_types": appointment_types, + "edit_visit_url": reverse('web.views.visit_details', args=(visit.id,)), + "add_appointment_url": reverse('web.views.appointment_add', args=(visit.id,)), "datetime_start": serialize_date(visit.datetime_begin), "datetime_end": serialize_date(visit.datetime_end), + "is_finished": visit.is_finished }) contact_reminder = serialize_datetime(study_subject.datetime_contact_reminder) contact_attempts = ContactAttempt.objects.filter(subject=study_subject).order_by("-datetime_when") diff --git a/smash/web/decorators.py b/smash/web/decorators.py new file mode 100644 index 0000000000000000000000000000000000000000..fed40f38b0a7cb104e0256d282581d09a204ba30 --- /dev/null +++ b/smash/web/decorators.py @@ -0,0 +1,112 @@ +# coding=utf-8 +import logging +from django.shortcuts import redirect +from django.contrib import messages +from web.models import Worker, WorkerStudyRole +from web.models.constants import GLOBAL_STUDY_ID +from django.http import HttpResponseForbidden +from django.contrib.auth.models import Permission +import functools +from collections import defaultdict +from django.views.generic.base import ContextMixin + +logger = logging.getLogger(__name__) + +''' + Dear developer reader, welcome to one of the most precious pieces of magic python can deliver. + This cute class decorator provides the same functionality as standard decorator functions, but + with the additional ability to keep a state along the decorated function calls. + + The decorator is used as follows: + @PermissionDecorator('change_worker') #codename of the permission + def worker_edit(request, worker_id): + ... + + In this case, this decorator class has two static variables, codenames and n_decorators. + The main question this decorator intends to answer is: + - Could I get all the codenames from all the decorators used along the code? + To do so, we have a static variable, codenames, and when an instance of the decorator + is created, the permission codename used in the decorator is stored. + + - Then, in the code, we could do: PermissionDecorator.codenames to access the list of + codenames used in the whole code. + + - We also have a static set of permissions, in which we can add the Permission object + obtained from the codename. This is also safe, since, if no Permission is found we can + raise an exception and avoid mid-runtime errors since this would be done during the + program initialization. + + - This solves the following problem: We wanted to have a list of the used codenames along + the code, so this used codenames would be visible, while the unused ones are kept hidden. + + This kind of decorators could also be used to register functions, having for example, a decorator + called @RegisterFunction that does not receive any argument, and hence, the __init__ method + would receive the decorated function instead of the decorator arguments. Or, if the decorator has + arguments, using the __call__ method to keep a static list of functions within the class. + + This way you could gather all the decorated functions to use them later, accessing the static + variables from the decorators. + + This is useful to avoid hardcoded lists of functions or decorator arguments. + + Two good references on the topic: + https://www.thecodeship.com/patterns/guide-to-python-function-decorators/ + https://realpython.com/primer-on-python-decorators/#classes-as-decorators +''' +class PermissionDecorator: + codenames = set() + permission_ids = set() + codename_groups = defaultdict(set) + permissions_queryset = None + n_decorators = 0 + + @staticmethod + def get_permissions(): + if PermissionDecorator.permissions_queryset is None or len(PermissionDecorator.codenames) > len(PermissionDecorator.permissions_queryset): + PermissionDecorator.permissions_queryset = Permission.objects.filter(codename__in=PermissionDecorator.codenames) + + return PermissionDecorator.permissions_queryset + + def __init__(self, perm_codename, group=None): + ''' + This method is called when the code is interpreted, this is, when a function is decorated + because an instance of the decorator is created. + ''' + PermissionDecorator.codenames.add(perm_codename) #register permission codename + PermissionDecorator.n_decorators += 1 #count number of decorators + + if group is not None: + PermissionDecorator.codename_groups[group].add(perm_codename) + + #variables to be used on decorator call + self.perm_codename = perm_codename + + def __call__(self, func): + ''' + This method is also called when the function is decorated + ''' + def func_wrapper(thing, *args, **kwargs): + ''' + This method is called when the decorated function is called + ''' + if isinstance(thing, ContextMixin): + request = thing.request + else: + request = thing + + if request.user.is_superuser: + return func(thing, *args, **kwargs) + else: + worker = Worker.get_by_user(request.user) + roles = WorkerStudyRole.objects.filter(worker=worker, study_id=GLOBAL_STUDY_ID) + if roles.count() > 0: + permissions = roles[0].permissions.filter(codename=self.perm_codename) + if len(permissions) > 0: + return func(thing, *args, **kwargs) + messages.error(request, 'You are not authorized to view this page. Request permissions to the system administrator.') + #avoid loops if the HTTP_REFERER header is set to the visited URL + http_referer = request.META.get('HTTP_REFERER', 'web.views.index') + if http_referer == request.build_absolute_uri() or http_referer == request.path: + http_referer = 'web.views.index' + return redirect(http_referer) + return func_wrapper \ No newline at end of file diff --git a/smash/web/forms/forms.py b/smash/web/forms/forms.py index 3106fba657d935031fcf148a5cbe6c253dc6c9d2..acead32df6e5e1401a5346ecbec59be00aac8d8d 100644 --- a/smash/web/forms/forms.py +++ b/smash/web/forms/forms.py @@ -60,6 +60,14 @@ class VisitDetailForm(ModelForm): appointment_types = forms.ModelMultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, queryset=AppointmentType.objects.all()) + def __init__(self, *args, **kwargs): + super(VisitDetailForm, self).__init__(*args, **kwargs) + instance = getattr(self, 'instance', None) + if instance.is_finished: #set form as readonly + for key in self.fields.keys(): + self.fields[key].widget.attrs['readonly'] = True + + class Meta: model = Visit exclude = ['is_finished', 'visit_number'] diff --git a/smash/web/forms/study_forms.py b/smash/web/forms/study_forms.py index 6e827cf3282821cd482ae0f933e6cf1754a5d903..df1874fa316d955ecd36530e99fa7f8866866738 100644 --- a/smash/web/forms/study_forms.py +++ b/smash/web/forms/study_forms.py @@ -3,6 +3,9 @@ import logging from django.forms import ModelForm, ValidationError from web.models import Study, StudyNotificationParameters, StudyColumns, StudySubject +import datetime +from dateutil.relativedelta import relativedelta + logger = logging.getLogger(__name__) @@ -11,17 +14,35 @@ class StudyEditForm(ModelForm): def __init__(self, *args, **kwargs): super(StudyEditForm, self).__init__(*args, **kwargs) - def clean_nd_number_study_subject_regex(self): - nd_number_study_subject_regex = self.cleaned_data.get( - 'nd_number_study_subject_regex') + def clean(self): + cleaned_data = super(StudyEditForm, self).clean() + #check regex + nd_number_study_subject_regex = cleaned_data.get('nd_number_study_subject_regex') + instance = getattr(self, 'instance', None) - if StudySubject.check_nd_number_regex(nd_number_study_subject_regex, instance) == False: - raise ValidationError( - 'Please enter a valid nd_number_study_subject_regex regex.') - - return nd_number_study_subject_regex + if nd_number_study_subject_regex is None or StudySubject.check_nd_number_regex(nd_number_study_subject_regex, instance) == False: + self.add_error('nd_number_study_subject_regex', 'Please enter a valid nd_number_study_subject_regex regex.') + + #check default_visit_duration_in_months + visit_duration_in_months = cleaned_data.get('default_visit_duration_in_months') + control_follow_up = cleaned_data.get('default_delta_time_for_control_follow_up') + patient_follow_up = cleaned_data.get('default_delta_time_for_patient_follow_up') + units = cleaned_data.get('default_delta_time_for_follow_up_units') + + if None not in [visit_duration_in_months, control_follow_up, patient_follow_up, units]: + t = datetime.datetime.today() + visit_duration = relativedelta(months=int(visit_duration_in_months)) + control_delta = relativedelta(**{units: control_follow_up}) + patient_delta = relativedelta(**{units: patient_follow_up}) + + #relative time delta has no __cmp__ method, so we add them to a datetime + min_delta_time = min((t + control_delta), (t + patient_delta)) + if (t+visit_duration) > min_delta_time: + self.add_error('default_visit_duration_in_months', 'Please enter a valid "duration of the visits". It must be shorter than the time difference between patient and control visits.') + + return cleaned_data class Meta: model = Study diff --git a/smash/web/forms/worker_form.py b/smash/web/forms/worker_form.py index 8835f9168e03e50fc18823c2e453cdaf2bb2f48e..8ceeacd7c53312247f2493eb76d03da137543a19 100644 --- a/smash/web/forms/worker_form.py +++ b/smash/web/forms/worker_form.py @@ -10,6 +10,7 @@ from web.models import Worker, WorkerStudyRole from web.models.constants import GLOBAL_STUDY_ID from web.models.worker import role_choices_by_worker_type, worker_type_by_worker from web.models.worker_study_role import WORKER_STAFF, WORKER_VOUCHER_PARTNER, WORKER_HEALTH_PARTNER +from web.decorators import PermissionDecorator logger = logging.getLogger(__name__) @@ -25,12 +26,14 @@ class WorkerForm(ModelForm): instance = getattr(self, 'instance', None) initial_role = None + initial_permissions = None if instance is not None and instance.pk: worker_type = worker_type_by_worker(instance) roles = WorkerStudyRole.objects.filter(worker=instance, study_id=GLOBAL_STUDY_ID) if roles.count() > 0: initial_role = roles[0].role + initial_permissions = roles[0].permissions.all() choices = role_choices_by_worker_type(worker_type) @@ -46,10 +49,18 @@ class WorkerForm(ModelForm): self.fields['role'] = forms.ChoiceField(label='Role', choices=choices) self.fields['role'].initial = initial_role + #use only the codename used in the code decorators + self.fields['permissions'] = forms.ModelMultipleChoiceField(required=False, queryset=PermissionDecorator.get_permissions()) + if initial_permissions is not None: + self.fields['permissions'].initial = [c.pk for c in initial_permissions] del self.fields['user'] if worker_type == WORKER_STAFF: + if instance.user is not None: + self.fields['Superuser'] = forms.BooleanField(label='Is Superuser?', disabled=True, required=False, + help_text='Super users have all permissions. This is a read only field.') + self.fields['Superuser'].initial = instance.user.is_superuser del self.fields['voucher_types'] del self.fields['name'] else: @@ -90,9 +101,14 @@ class WorkerForm(ModelForm): roles = WorkerStudyRole.objects.filter(worker=instance, study_id=GLOBAL_STUDY_ID) if roles.count() > 0: - roles.update(role=self.cleaned_data['role']) + for role in roles: #should be only one + role.role=self.cleaned_data['role'] + role.permissions.set(self.cleaned_data['permissions']) + role.save() else: - WorkerStudyRole.objects.create(worker=instance, study_id=GLOBAL_STUDY_ID, role=self.cleaned_data['role']) + role = WorkerStudyRole.objects.create(worker=instance, study_id=GLOBAL_STUDY_ID, role=self.cleaned_data['role']) + role.permissions.set(self.cleaned_data['permissions']) + role.save() def clean(self): cleaned_data = super(WorkerForm, self).clean() diff --git a/smash/web/management/commands/holidays.py b/smash/web/management/commands/holidays.py index 7c01d080eecf0b2718506b3c7a33eebc566cf3ba..5b729987a2673ae3c3503e50efc1228685654e81 100644 --- a/smash/web/management/commands/holidays.py +++ b/smash/web/management/commands/holidays.py @@ -4,8 +4,6 @@ from django.core.management.base import BaseCommand from ...models import Appointment, Location, AppointmentType, AppointmentTypeLink -appointment_type_other = AppointmentType.objects.filter(code='OTHER').first() - def get_easter_monday(easter_sunday): return next_weekday(easter_sunday, 0) @@ -64,6 +62,7 @@ class Command(BaseCommand): holiday.comment = comment holiday.visit_id = None holiday.save() + appointment_type_other, _ = AppointmentType.objects.get_or_create(code='OTHER', defaults={'default_duration': 60}) link = AppointmentTypeLink(appointment=holiday, appointment_type=appointment_type_other) link.save() diff --git a/smash/web/migrations/0132_study_default_visit_duration_in_months.py b/smash/web/migrations/0132_study_default_visit_duration_in_months.py new file mode 100644 index 0000000000000000000000000000000000000000..522e672e1041241ab5c52140cebbbc53b8be7bbc --- /dev/null +++ b/smash/web/migrations/0132_study_default_visit_duration_in_months.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-11-13 10:05 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0131_study_default_voucher_expiration_in_months'), + ] + + operations = [ + migrations.AddField( + model_name='study', + name='default_visit_duration_in_months', + field=models.IntegerField(default=3, validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Default duration of the visits in months'), + ), + ] diff --git a/smash/web/migrations/0132_workerstudyrole_permissions.py b/smash/web/migrations/0132_workerstudyrole_permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..58d0fc3b90139a91371aea5c14249e66a6481ebc --- /dev/null +++ b/smash/web/migrations/0132_workerstudyrole_permissions.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-11-19 10:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + ('web', '0131_study_default_voucher_expiration_in_months'), + ] + + operations = [ + migrations.AddField( + model_name='workerstudyrole', + name='permissions', + field=models.ManyToManyField(blank=True, to='auth.Permission', verbose_name=b'Worker Study Permissions'), + ), + ] diff --git a/smash/web/migrations/0133_auto_20181113_1550.py b/smash/web/migrations/0133_auto_20181113_1550.py new file mode 100644 index 0000000000000000000000000000000000000000..efc19768b94521fcc1c12fcdaf030d640d94a8f7 --- /dev/null +++ b/smash/web/migrations/0133_auto_20181113_1550.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-11-13 15:50 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0132_study_default_visit_duration_in_months'), + ] + + operations = [ + migrations.AddField( + model_name='study', + name='default_delta_time_for_control_follow_up', + field=models.IntegerField(default=4, help_text=b'Time difference between visits used to automatically create follow up visits', validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Time difference between control visits'), + ), + migrations.AddField( + model_name='study', + name='default_delta_time_for_follow_up_units', + field=models.CharField(choices=[(b'days', b'Days'), (b'years', b'Years')], default=b'years', help_text=b'Units for the number of days between visits for both patients and controls', max_length=10, verbose_name=b'Units for the follow up incrementals'), + ), + migrations.AddField( + model_name='study', + name='default_delta_time_for_patient_follow_up', + field=models.IntegerField(default=1, help_text=b'Time difference between visits used to automatically create follow up visits', validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Time difference between patient visits'), + ), + migrations.AlterField( + model_name='study', + name='default_visit_duration_in_months', + field=models.IntegerField(default=6, help_text=b'Duration of the visit, this is, the time interval, in months, when the appointments may take place', validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Duration of the visits in months'), + ), + migrations.AlterField( + model_name='study', + name='default_voucher_expiration_in_months', + field=models.IntegerField(default=3, validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Duration of the vouchers in months'), + ), + ] diff --git a/smash/web/migrations/0134_merge_20181211_1542.py b/smash/web/migrations/0134_merge_20181211_1542.py new file mode 100644 index 0000000000000000000000000000000000000000..9ea20794127870e032566c49af3e2d438e0c7acd --- /dev/null +++ b/smash/web/migrations/0134_merge_20181211_1542.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-12-11 15:42 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0132_workerstudyrole_permissions'), + ('web', '0133_auto_20181113_1550'), + ] + + operations = [ + ] diff --git a/smash/web/migrations/0135_merge_20181212_1333.py b/smash/web/migrations/0135_merge_20181212_1333.py new file mode 100644 index 0000000000000000000000000000000000000000..2bfc9cb114af90acd1de3133b863949ccefe8395 --- /dev/null +++ b/smash/web/migrations/0135_merge_20181212_1333.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-12-12 13:33 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0134_merge_20181211_1542'), + ('web', '0132_worker_comment'), + ] + + operations = [ + ] diff --git a/smash/web/models/study.py b/smash/web/models/study.py index e89ac16fc1f491a335b770d6e953b127227771bd..b4e9dfa5a1410cfd82d4a6b2d42a915cb9f81f57 100644 --- a/smash/web/models/study.py +++ b/smash/web/models/study.py @@ -6,6 +6,12 @@ from django.core.validators import MaxValueValidator, MinValueValidator import re +FOLLOW_UP_INCREMENT_IN_YEARS = 'years' +FOLLOW_UP_INCREMENT_IN_DAYS = 'days' +FOLLOW_UP_INCREMENT_UNIT_CHOICE = { + FOLLOW_UP_INCREMENT_IN_YEARS: 'Years', + FOLLOW_UP_INCREMENT_IN_DAYS: 'Days' +} class Study(models.Model): @@ -39,11 +45,40 @@ class Study(models.Model): ) default_voucher_expiration_in_months = models.IntegerField( - verbose_name='Default duration of the vouchers in months', + verbose_name='Duration of the vouchers in months', default=3, validators=[MinValueValidator(1)] ) + default_visit_duration_in_months = models.IntegerField( + verbose_name='Duration of the visits in months', + help_text='Duration of the visit, this is, the time interval, in months, when the appointments may take place', + default=6, + validators=[MinValueValidator(1)] + ) + + default_delta_time_for_patient_follow_up = models.IntegerField( + verbose_name='Time difference between patient visits', + help_text='Time difference between visits used to automatically create follow up visits', + default=1, + validators=[MinValueValidator(1)] + ) + + default_delta_time_for_control_follow_up = models.IntegerField( + verbose_name='Time difference between control visits', + help_text='Time difference between visits used to automatically create follow up visits', + default=4, + validators=[MinValueValidator(1)] + ) + + default_delta_time_for_follow_up_units = models.CharField(max_length=10, + choices=FOLLOW_UP_INCREMENT_UNIT_CHOICE.items(), + verbose_name='Units for the follow up incrementals', + help_text='Units for the number of days between visits for both patients and controls', + default=FOLLOW_UP_INCREMENT_IN_YEARS, + blank=False + ) + def check_nd_number(self, nd_number): regex = re.compile(self.nd_number_study_subject_regex) return regex.match(nd_number) is not None diff --git a/smash/web/models/visit.py b/smash/web/models/visit.py index 47ac3d8a7287d4bc57395a91e265a1b89f49a69f..c2b00ebb5056edda65023becaba5a6d126959ea6 100644 --- a/smash/web/models/visit.py +++ b/smash/web/models/visit.py @@ -1,12 +1,17 @@ # coding=utf-8 import datetime +from dateutil.relativedelta import relativedelta from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver +from django.db import transaction from web.models.constants import BOOL_CHOICES, SUBJECT_TYPE_CHOICES_CONTROL +from web.models import Study +import logging +logger = logging.getLogger(__name__) class Visit(models.Model): @@ -68,30 +73,46 @@ class Visit(models.Model): follow_up_number = Visit.objects.filter( subject=self.subject).count() + 1 - delta_days = 365 + study = self.subject.study + if self.subject.type == SUBJECT_TYPE_CHOICES_CONTROL: - delta_days = 365 * 3 + 366 + args = {study.default_delta_time_for_follow_up_units: study.default_delta_time_for_control_follow_up} + else: + args = {study.default_delta_time_for_follow_up_units: study.default_delta_time_for_patient_follow_up} + + time_to_next_visit = relativedelta(**args) * (follow_up_number - 1) #calculated from first visit - time_to_next_visit = datetime.timedelta( - days=delta_days * (follow_up_number - 1)) + logger.warn('new visit: {} {} {}'.format(args, relativedelta(**args), time_to_next_visit)) Visit.objects.create( subject=self.subject, datetime_begin=visit_started + time_to_next_visit, - datetime_end=visit_started + time_to_next_visit + - datetime.timedelta(days=93) + datetime_end=visit_started + time_to_next_visit + relativedelta(months=study.default_visit_duration_in_months) ) - @receiver(post_save, sender=Visit) -def update_visit_number(sender, instance, **kwargs): +def check_visit_number(sender, instance, created, **kwargs): + # no other solution to ensure the visit_number is in cronological order than to sort the whole list if there are future visits visit = instance - if visit.subject is not None: - count = Visit.objects.filter(subject=visit.subject).filter( - datetime_begin__lte=visit.datetime_begin).count() - if count != visit.visit_number: - visit.visit_number = count - visit.save() - subject_visits = Visit.objects.filter(subject=visit.subject).all() - for subject_visit in subject_visits: - update_visit_number(sender, subject_visit) + if visit.subject is not None: #not sure if select_for_update has an effect, the tests work as well without it + #new visit, sort only future visit respect to the new one + if created: + visits_before = Visit.objects.select_for_update().filter(subject=visit.subject).filter(datetime_begin__lt=visit.datetime_begin).count() + # we need to sort the future visits respect to the new one, if any + visits = Visit.objects.select_for_update().filter(subject=visit.subject).filter(datetime_begin__gte=visit.datetime_begin).order_by('datetime_begin','datetime_end') + with transaction.atomic(): #not sure if it has an effect, the tests work as well without it + for i, v in enumerate(visits): + expected_visit_number = (visits_before + i + 1) + if v.visit_number != expected_visit_number: + Visit.objects.filter(id=v.id).update(visit_number=expected_visit_number) # does not rise post_save, we avoid recursion + if v.id == visit.id: #if the iteration visit is the same that the instance that produced the signal call + #this ensures that the upper saved object is also updated, otherwise, refresh_from_db should be called + visit.visit_number = v.visit_number + else: + #if visits are modified, then, check everything + visits = Visit.objects.select_for_update().filter(subject=visit.subject).order_by('datetime_begin','datetime_end') + with transaction.atomic(): + for i, v in enumerate(visits): + expected_visit_number = (i+1) + if v.visit_number != expected_visit_number: #update only those with wrong numbers + Visit.objects.filter(id=v.id).update(visit_number=expected_visit_number) diff --git a/smash/web/models/worker.py b/smash/web/models/worker.py index 146a228e071f2dc78611912caf53e8d3904aea0b..d5b27d186ef7875cbf667920e645303e99f94c21 100644 --- a/smash/web/models/worker.py +++ b/smash/web/models/worker.py @@ -18,6 +18,7 @@ from web.models.holiday import Holiday from web.models.availability import Availability from web.models.appointment import Appointment from web.models.appointment_type_link import AppointmentTypeLink +from django.contrib.auth.models import Permission logger = logging.getLogger(__name__) @@ -159,6 +160,15 @@ class Worker(models.Model): return True return False + def current_leave_details(self): + holidays = self.holiday_set.filter(datetime_end__gt=datetime.datetime.now(), + datetime_start__lt=datetime.datetime.now(), + kind=AVAILABILITY_HOLIDAY).order_by('-datetime_end') + if len(holidays) > 0: + return holidays[0] + else: + return None + def disable(self): if self.user is not None: self.user.is_active = False @@ -233,6 +243,25 @@ class Worker(models.Model): return office_availability.get_availability_percentage(only_working_hours=True) + def get_permissions(self, study): + if self.user.is_superuser: + return set([p.codename for p in Permission.objects.all()]) + + roles = self.roles.filter(study=study) + if roles.count() == 0: + return set() + return set([p.codename for p in roles[0].permissions.all()]) + + def has_perm(self, codename, study): + roles = self.roles.filter(study=study) + if roles.count() == 0: + return False + + if role[0].permissions.filter(codename=codename).all().count() > 0: + return True + else: + return False + @property def role(self): roles = self.roles.filter(study=GLOBAL_STUDY_ID) diff --git a/smash/web/models/worker_study_role.py b/smash/web/models/worker_study_role.py index 2bd529c6942d3c4f819520d5dd91da3e2221c11d..b7da64abe15cc204222635a7556131d6c9a1ef37 100644 --- a/smash/web/models/worker_study_role.py +++ b/smash/web/models/worker_study_role.py @@ -2,6 +2,7 @@ import logging from django.db import models +from django.contrib.auth.models import Permission logger = logging.getLogger(__name__) @@ -52,3 +53,4 @@ class WorkerStudyRole(models.Model): role = models.CharField(max_length=20, choices=STUDY_ROLE_CHOICES, verbose_name='Role' ) + permissions = models.ManyToManyField(Permission, verbose_name='Worker Study Permissions', blank=True) \ No newline at end of file diff --git a/smash/web/static/AdminLTE/css/AdminLTE.css b/smash/web/static/AdminLTE/css/AdminLTE.css index a751788282389e6e0e24409055b6f81156de2808..17a9039c1515a6a01694e0f64d3415ec9a97a3c1 100644 --- a/smash/web/static/AdminLTE/css/AdminLTE.css +++ b/smash/web/static/AdminLTE/css/AdminLTE.css @@ -1107,7 +1107,7 @@ a:focus { border-top-left-radius: 0; padding: 1px 0 0 0; border-top-width: 0; - width: 280px; + width: 380px; } .navbar-nav > .user-menu > .dropdown-menu, .navbar-nav > .user-menu > .dropdown-menu > .user-body { @@ -1163,6 +1163,7 @@ a:focus { .navbar-nav > .user-menu > .dropdown-menu > .user-footer { background-color: #f9f9f9; padding: 10px; + text-align: center; } .navbar-nav > .user-menu > .dropdown-menu > .user-footer:before, .navbar-nav > .user-menu > .dropdown-menu > .user-footer:after { diff --git a/smash/web/static/AdminLTE/css/AdminLTE.min.css b/smash/web/static/AdminLTE/css/AdminLTE.min.css index bef3444798e268d366863acd61ccfc51700f665e..4312f7810672becc133fdaf252352bfe1e129fed 100644 --- a/smash/web/static/AdminLTE/css/AdminLTE.min.css +++ b/smash/web/static/AdminLTE/css/AdminLTE.min.css @@ -1,7 +1,7 @@ -@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic);/*! +@import"https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic";/*! * AdminLTE v2.3.7 * Author: Almsaeed Studio * Website: Almsaeed Studio <http://almsaeedstudio.com> * License: Open source - MIT * Please visit http://opensource.org/licenses/MIT for more information -!*/html,body{min-height:100%}.layout-boxed html,.layout-boxed body{height:100%}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:'Source Sans Pro','Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:400;overflow-x:hidden;overflow-y:auto}.wrapper{min-height:100%;position:relative;overflow:hidden}.wrapper:before,.wrapper:after{content:" ";display:table}.wrapper:after{clear:both}.layout-boxed .wrapper{max-width:1250px;margin:0 auto;min-height:100%;box-shadow:0 0 8px rgba(0,0,0,0.5);position:relative}.layout-boxed{background:url('../img/boxed-bg.jpg') repeat fixed}.content-wrapper,.right-side,.main-footer{-webkit-transition:-webkit-transform .3s ease-in-out,margin .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,margin .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,margin .3s ease-in-out;transition:transform .3s ease-in-out,margin .3s ease-in-out;margin-left:230px;z-index:820}.layout-top-nav .content-wrapper,.layout-top-nav .right-side,.layout-top-nav .main-footer{margin-left:0}@media(max-width:767px){.content-wrapper,.right-side,.main-footer{margin-left:0}}@media(min-width:768px){.sidebar-collapse .content-wrapper,.sidebar-collapse .right-side,.sidebar-collapse .main-footer{margin-left:0}}@media(max-width:767px){.sidebar-open .content-wrapper,.sidebar-open .right-side,.sidebar-open .main-footer{-webkit-transform:translate(230px,0);-ms-transform:translate(230px,0);-o-transform:translate(230px,0);transform:translate(230px,0)}}.content-wrapper,.right-side{min-height:100%;background-color:#ecf0f5;z-index:800}.main-footer{background:#fff;padding:15px;color:#444;border-top:1px solid #d2d6de}.fixed .main-header,.fixed .main-sidebar,.fixed .left-side{position:fixed}.fixed .main-header{top:0;right:0;left:0}.fixed .content-wrapper,.fixed .right-side{padding-top:50px}@media(max-width:767px){.fixed .content-wrapper,.fixed .right-side{padding-top:100px}}.fixed.layout-boxed .wrapper{max-width:100%}body.hold-transition .content-wrapper,body.hold-transition .right-side,body.hold-transition .main-footer,body.hold-transition .main-sidebar,body.hold-transition .left-side,body.hold-transition .main-header .navbar,body.hold-transition .main-header .logo{-webkit-transition:none;-o-transition:none;transition:none}.content{min-height:250px;padding:15px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:'Source Sans Pro',sans-serif}a{color:#3c8dbc}a:hover,a:active,a:focus{outline:0;text-decoration:none;color:#72afd2}.page-header{margin:10px 0 20px 0;font-size:22px}.page-header>small{color:#666;display:block;margin-top:5px}.main-header{position:relative;max-height:100px;z-index:1030}.main-header .navbar{-webkit-transition:margin-left .3s ease-in-out;-o-transition:margin-left .3s ease-in-out;transition:margin-left .3s ease-in-out;margin-bottom:0;margin-left:230px;border:0;min-height:50px;border-radius:0}.layout-top-nav .main-header .navbar{margin-left:0}.main-header #navbar-search-input.form-control{background:rgba(255,255,255,0.2);border-color:transparent}.main-header #navbar-search-input.form-control:focus,.main-header #navbar-search-input.form-control:active{border-color:rgba(0,0,0,0.1);background:rgba(255,255,255,0.9)}.main-header #navbar-search-input.form-control::-moz-placeholder{color:#ccc;opacity:1}.main-header #navbar-search-input.form-control:-ms-input-placeholder{color:#ccc}.main-header #navbar-search-input.form-control::-webkit-input-placeholder{color:#ccc}.main-header .navbar-custom-menu,.main-header .navbar-right{float:right}@media(max-width:991px){.main-header .navbar-custom-menu a,.main-header .navbar-right a{color:inherit;background:transparent}}@media(max-width:767px){.main-header .navbar-right{float:none}.navbar-collapse .main-header .navbar-right{margin:7.5px -15px}.main-header .navbar-right>li{color:inherit;border:0}}.main-header .sidebar-toggle{float:left;background-color:transparent;background-image:none;padding:15px 15px;font-family:fontAwesome}.main-header .sidebar-toggle:before{content:"\f0c9"}.main-header .sidebar-toggle:hover{color:#fff}.main-header .sidebar-toggle:focus,.main-header .sidebar-toggle:active{background:transparent}.main-header .sidebar-toggle .icon-bar{display:none}.main-header .no_worker_warning{float:left;color:white;font-weight:600;letter-spacing:.25px;border-bottom:#dd4b39 solid 2px;margin-top:12px;padding:3px 3px 3px 5px;transition:1s}.main-header .no_worker_warning:hover{color:red;background-color:black;opacity:1;border-bottom:black none 2px;border-radius:5px;transition:1s}.main-header .no_worker_warning>i.fa{padding:2px 5px 2px 2px;color:#dd4b39;text-shadow:0 0 1px #000}.main-header .navbar .nav>li.user>a>.fa,.main-header .navbar .nav>li.user>a>.glyphicon,.main-header .navbar .nav>li.user>a>.ion{margin-right:5px}.main-header .navbar .nav>li>a>.label{position:absolute;top:9px;right:7px;text-align:center;font-size:9px;padding:2px 3px;line-height:.9}.main-header .logo{-webkit-transition:width .3s ease-in-out;-o-transition:width .3s ease-in-out;transition:width .3s ease-in-out;display:block;float:left;height:50px;font-size:20px;line-height:50px;text-align:center;width:230px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;padding:0 15px;font-weight:300;overflow:hidden}.main-header .logo .logo-lg{display:block}.main-header .logo .logo-mini{display:none}.main-header .navbar-brand{color:#fff}.content-header{position:relative;padding:15px 15px 0 15px}.content-header>h1{margin:0;font-size:24px}.content-header>h1>small{font-size:15px;display:inline-block;padding-left:4px;font-weight:300}.content-header>.breadcrumb{float:right;background:transparent;margin-top:0;margin-bottom:0;font-size:12px;padding:7px 5px;position:absolute;top:15px;right:10px;border-radius:2px}.content-header>.breadcrumb>li>a{color:#444;text-decoration:none;display:inline-block}.content-header>.breadcrumb>li>a>.fa,.content-header>.breadcrumb>li>a>.glyphicon,.content-header>.breadcrumb>li>a>.ion{margin-right:5px}.content-header>.breadcrumb>li+li:before{content:'>\00a0'}@media(max-width:991px){.content-header>.breadcrumb{position:relative;margin-top:5px;top:0;right:0;float:none;background:#d2d6de;padding-left:10px}.content-header>.breadcrumb li:before{color:#97a0b3}}.navbar-toggle{color:#fff;border:0;margin:0;padding:15px 15px}@media(max-width:991px){.navbar-custom-menu .navbar-nav>li{float:left}.navbar-custom-menu .navbar-nav{margin:0;float:left}.navbar-custom-menu .navbar-nav>li>a{padding-top:15px;padding-bottom:15px;line-height:20px}}@media(max-width:767px){.main-header{position:relative}.main-header .logo,.main-header .navbar{width:100%;float:none}.main-header .navbar{margin:0}.main-header .navbar-custom-menu{float:right}}@media(max-width:991px){.navbar-collapse.pull-left{float:none !important}.navbar-collapse.pull-left+.navbar-custom-menu{display:block;position:absolute;top:0;right:40px}}.main-sidebar,.left-side{position:absolute;top:0;left:0;padding-top:50px;min-height:100%;width:230px;z-index:810;-webkit-transition:-webkit-transform .3s ease-in-out,width .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,width .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,width .3s ease-in-out;transition:transform .3s ease-in-out,width .3s ease-in-out}@media(max-width:767px){.main-sidebar,.left-side{padding-top:100px}}@media(max-width:767px){.main-sidebar,.left-side{-webkit-transform:translate(-230px,0);-ms-transform:translate(-230px,0);-o-transform:translate(-230px,0);transform:translate(-230px,0)}}@media(min-width:768px){.sidebar-collapse .main-sidebar,.sidebar-collapse .left-side{-webkit-transform:translate(-230px,0);-ms-transform:translate(-230px,0);-o-transform:translate(-230px,0);transform:translate(-230px,0)}}@media(max-width:767px){.sidebar-open .main-sidebar,.sidebar-open .left-side{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}}.sidebar{padding-bottom:10px}.sidebar-form input:focus{border-color:transparent}.user-panel{position:relative;width:100%;padding:10px;overflow:hidden}.user-panel:before,.user-panel:after{content:" ";display:table}.user-panel:after{clear:both}.user-panel>.image>img{width:100%;max-width:45px;height:auto}.user-panel>.info{padding:5px 5px 5px 15px;line-height:1;position:absolute;left:55px}.user-panel>.info>p{font-weight:600;margin-bottom:9px}.user-panel>.info>a{text-decoration:none;padding-right:5px;margin-top:3px;font-size:11px}.user-panel>.info>a>.fa,.user-panel>.info>a>.ion,.user-panel>.info>a>.glyphicon{margin-right:3px}.sidebar-menu{list-style:none;margin:0;padding:0}.sidebar-menu>li{position:relative;margin:0;padding:0}.sidebar-menu>li>a{padding:12px 5px 12px 15px;display:block}.sidebar-menu>li>a>.fa,.sidebar-menu>li>a>.glyphicon,.sidebar-menu>li>a>.ion{width:20px}.sidebar-menu>li .label,.sidebar-menu>li .badge{margin-right:5px}.sidebar-menu>li .badge{margin-top:3px}.sidebar-menu li.header{padding:10px 25px 10px 15px;font-size:12px}.sidebar-menu li>a>.fa-angle-left,.sidebar-menu li>a>.pull-right-container>.fa-angle-left{width:auto;height:auto;padding:0;margin-right:10px}.sidebar-menu li.active>a>.fa-angle-left,.sidebar-menu li.active>a>.pull-right-container>.fa-angle-left{-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.sidebar-menu li.active>.treeview-menu{display:block}.sidebar-menu .treeview-menu{display:none;list-style:none;padding:0;margin:0;padding-left:5px}.sidebar-menu .treeview-menu .treeview-menu{padding-left:20px}.sidebar-menu .treeview-menu>li{margin:0}.sidebar-menu .treeview-menu>li>a{padding:5px 5px 5px 15px;display:block;font-size:14px}.sidebar-menu .treeview-menu>li>a>.fa,.sidebar-menu .treeview-menu>li>a>.glyphicon,.sidebar-menu .treeview-menu>li>a>.ion{width:20px}.sidebar-menu .treeview-menu>li>a>.pull-right-container>.fa-angle-left,.sidebar-menu .treeview-menu>li>a>.pull-right-container>.fa-angle-down,.sidebar-menu .treeview-menu>li>a>.fa-angle-left,.sidebar-menu .treeview-menu>li>a>.fa-angle-down{width:auto}@media(min-width:768px){.sidebar-mini.sidebar-collapse .content-wrapper,.sidebar-mini.sidebar-collapse .right-side,.sidebar-mini.sidebar-collapse .main-footer{margin-left:50px !important;z-index:840}.sidebar-mini.sidebar-collapse .main-sidebar{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0);width:50px !important;z-index:850}.sidebar-mini.sidebar-collapse .sidebar-menu>li{position:relative}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a{margin-right:0}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span{border-top-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:not(.treeview)>a>span{border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{padding-top:5px;padding-bottom:5px;border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>span:not(.pull-right),.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{display:block !important;position:absolute;width:180px;left:50px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>span{top:0;margin-left:-3px;padding:12px 5px 12px 20px;background-color:inherit}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>.pull-right-container{float:right;width:auto !important;left:200px !important;top:10px !important}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>.pull-right-container>.label:not(:first-of-type){display:none}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{top:44px;margin-left:0}.sidebar-mini.sidebar-collapse .main-sidebar .user-panel>.info,.sidebar-mini.sidebar-collapse .sidebar-form,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span,.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>.pull-right,.sidebar-mini.sidebar-collapse .sidebar-menu li.header{display:none !important;-webkit-transform:translateZ(0)}.sidebar-mini.sidebar-collapse .main-header .logo{width:50px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-mini{display:block;margin-left:-15px;margin-right:-15px;font-size:18px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-lg{display:none}.sidebar-mini.sidebar-collapse .main-header .navbar{margin-left:50px}}.sidebar-menu,.main-sidebar .user-panel,.sidebar-menu>li.header{white-space:nowrap;overflow:hidden}.sidebar-menu:hover{overflow:visible}.sidebar-form,.sidebar-menu>li.header{overflow:hidden;text-overflow:clip}.sidebar-menu li>a{position:relative}.sidebar-menu li>a>.pull-right-container{position:absolute;right:10px;top:50%;margin-top:-7px}.control-sidebar-bg{position:fixed;z-index:1000;bottom:0}.control-sidebar-bg,.control-sidebar{top:0;right:-230px;width:230px;-webkit-transition:right .3s ease-in-out;-o-transition:right .3s ease-in-out;transition:right .3s ease-in-out}.control-sidebar{position:absolute;padding-top:50px;z-index:1010}@media(max-width:768px){.control-sidebar{padding-top:100px}}.control-sidebar>.tab-content{padding:10px 15px}.control-sidebar.control-sidebar-open,.control-sidebar.control-sidebar-open+.control-sidebar-bg{right:0}.control-sidebar-open .control-sidebar-bg,.control-sidebar-open .control-sidebar{right:0}@media(min-width:768px){.control-sidebar-open .content-wrapper,.control-sidebar-open .right-side,.control-sidebar-open .main-footer{margin-right:230px}}.nav-tabs.control-sidebar-tabs>li:first-of-type>a,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:hover,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:focus{border-left-width:0}.nav-tabs.control-sidebar-tabs>li>a{border-radius:0}.nav-tabs.control-sidebar-tabs>li>a,.nav-tabs.control-sidebar-tabs>li>a:hover{border-top:0;border-right:0;border-left:1px solid transparent;border-bottom:1px solid transparent}.nav-tabs.control-sidebar-tabs>li>a .icon{font-size:16px}.nav-tabs.control-sidebar-tabs>li.active>a,.nav-tabs.control-sidebar-tabs>li.active>a:hover,.nav-tabs.control-sidebar-tabs>li.active>a:focus,.nav-tabs.control-sidebar-tabs>li.active>a:active{border-top:0;border-right:0;border-bottom:0}@media(max-width:768px){.nav-tabs.control-sidebar-tabs{display:table}.nav-tabs.control-sidebar-tabs>li{display:table-cell}}.control-sidebar-heading{font-weight:400;font-size:16px;padding:10px 0;margin-bottom:10px}.control-sidebar-subheading{display:block;font-weight:400;font-size:14px}.control-sidebar-menu{list-style:none;padding:0;margin:0 -15px}.control-sidebar-menu>li>a{display:block;padding:10px 15px}.control-sidebar-menu>li>a:before,.control-sidebar-menu>li>a:after{content:" ";display:table}.control-sidebar-menu>li>a:after{clear:both}.control-sidebar-menu>li>a>.control-sidebar-subheading{margin-top:0}.control-sidebar-menu .menu-icon{float:left;width:35px;height:35px;border-radius:50%;text-align:center;line-height:35px}.control-sidebar-menu .menu-info{margin-left:45px;margin-top:3px}.control-sidebar-menu .menu-info>.control-sidebar-subheading{margin:0}.control-sidebar-menu .menu-info>p{margin:0;font-size:11px}.control-sidebar-menu .progress{margin:0}.control-sidebar-dark{color:#b8c7ce}.control-sidebar-dark,.control-sidebar-dark+.control-sidebar-bg{background:#222d32}.control-sidebar-dark .nav-tabs.control-sidebar-tabs{border-bottom:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a{background:#181f23;color:#b8c7ce}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#141a1d;border-bottom-color:#141a1d}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:active{background:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover{color:#fff}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#222d32;color:#fff}.control-sidebar-dark .control-sidebar-heading,.control-sidebar-dark .control-sidebar-subheading{color:#fff}.control-sidebar-dark .control-sidebar-menu>li>a:hover{background:#1e282c}.control-sidebar-dark .control-sidebar-menu>li>a .menu-info>p{color:#b8c7ce}.control-sidebar-light{color:#5e5e5e}.control-sidebar-light,.control-sidebar-light+.control-sidebar-bg{background:#f9fafc;border-left:1px solid #d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs{border-bottom:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a{background:#e8ecf4;color:#444}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#d2d6de;border-bottom-color:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:active{background:#eff1f7}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#f9fafc;color:#111}.control-sidebar-light .control-sidebar-heading,.control-sidebar-light .control-sidebar-subheading{color:#111}.control-sidebar-light .control-sidebar-menu{margin-left:-14px}.control-sidebar-light .control-sidebar-menu>li>a:hover{background:#f4f4f5}.control-sidebar-light .control-sidebar-menu>li>a .menu-info>p{color:#5e5e5e}.dropdown-menu{box-shadow:none;border-color:#eee}.dropdown-menu>li>a{color:#777}.dropdown-menu>li>a>.glyphicon,.dropdown-menu>li>a>.fa,.dropdown-menu>li>a>.ion{margin-right:10px}.dropdown-menu>li>a:hover{background-color:#e1e3e9;color:#333}.dropdown-menu>.divider{background-color:#eee}.navbar-nav>.notifications-menu>.dropdown-menu,.navbar-nav>.messages-menu>.dropdown-menu,.navbar-nav>.tasks-menu>.dropdown-menu{width:280px;padding:0;margin:0;top:100%}.navbar-nav>.notifications-menu>.dropdown-menu>li,.navbar-nav>.messages-menu>.dropdown-menu>li,.navbar-nav>.tasks-menu>.dropdown-menu>li{position:relative}.navbar-nav>.notifications-menu>.dropdown-menu>li.header,.navbar-nav>.messages-menu>.dropdown-menu>li.header,.navbar-nav>.tasks-menu>.dropdown-menu>li.header{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#fff;padding:7px 10px;border-bottom:1px solid #f4f4f4;color:#444;font-size:14px}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;font-size:12px;background-color:#fff;padding:7px 10px;border-bottom:1px solid #eee;color:#444 !important;text-align:center}@media(max-width:991px){.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{background:#fff !important;color:#444 !important}}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a:hover{text-decoration:none;font-weight:normal}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu,.navbar-nav>.messages-menu>.dropdown-menu>li .menu,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu{max-height:200px;margin:0;padding:0;list-style:none;overflow-x:hidden}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{display:block;white-space:nowrap;border-bottom:1px solid #f4f4f4}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a:hover{background:#f4f4f4;text-decoration:none}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a{color:#444;overflow:hidden;text-overflow:ellipsis;padding:10px}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.glyphicon,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.fa,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.ion{width:20px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a{margin:0;padding:10px 10px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>div>img{margin:auto 10px auto auto;width:40px;height:40px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4{padding:0;margin:0 0 0 45px;color:#444;font-size:15px;position:relative}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4>small{color:#999;font-size:10px;position:absolute;top:0;right:0}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>p{margin:0 0 0 45px;font-size:12px;color:#888}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:before,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{content:" ";display:table}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{clear:both}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{padding:10px}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>h3{font-size:14px;padding:0;margin:0 0 10px 0;color:#666}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>.progress{padding:0;margin:0}.navbar-nav>.user-menu>.dropdown-menu{border-top-right-radius:0;border-top-left-radius:0;padding:1px 0 0 0;border-top-width:0;width:280px}.navbar-nav>.user-menu>.dropdown-menu,.navbar-nav>.user-menu>.dropdown-menu>.user-body{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header{height:175px;padding:10px;text-align:center}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>img{z-index:5;height:90px;width:90px;border:3px solid;border-color:transparent;border-color:rgba(255,255,255,0.2)}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p{z-index:5;color:#fff;color:rgba(255,255,255,0.8);font-size:17px;margin-top:10px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p>small{display:block;font-size:12px}.navbar-nav>.user-menu>.dropdown-menu>.user-body{padding:15px;border-bottom:1px solid #f4f4f4;border-top:1px solid #ddd}.navbar-nav>.user-menu>.dropdown-menu>.user-body:before,.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-body a{color:#444 !important}@media(max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-body a{background:#fff !important;color:#444 !important}}.navbar-nav>.user-menu>.dropdown-menu>.user-footer{background-color:#f9f9f9;padding:10px}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:before,.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default{color:#666}@media(max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default:hover{background-color:#f9f9f9}}.navbar-nav>.user-menu .user-image{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px;margin-top:-2px}@media(max-width:767px){.navbar-nav>.user-menu .user-image{float:none;margin-right:0;margin-top:-8px;line-height:10px}}.open:not(.dropup)>.animated-dropdown-menu{backface-visibility:visible !important;-webkit-animation:flipInX .7s both;-o-animation:flipInX .7s both;animation:flipInX .7s both}@keyframes flipInX{0%{transform:perspective(400px) rotate3d(1,0,0,90deg);transition-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1,0,0,-20deg);transition-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{transform:perspective(400px)}}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px)}}.navbar-custom-menu>.navbar-nav>li{position:relative}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:0;left:auto}@media(max-width:991px){.navbar-custom-menu>.navbar-nav{float:right}.navbar-custom-menu>.navbar-nav>li{position:static}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:5%;left:auto;border:1px solid #ddd;background:#fff}}.form-control{border-radius:0;box-shadow:none;border-color:#d2d6de}.form-control:focus{border-color:#3c8dbc;box-shadow:none}.form-control::-moz-placeholder,.form-control:-ms-input-placeholder,.form-control::-webkit-input-placeholder{color:#bbb;opacity:1}.form-control:not(select){-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-group.has-success label{color:#00a65a}.form-group.has-success .form-control,.form-group.has-success .input-group-addon{border-color:#00a65a;box-shadow:none}.form-group.has-success .help-block{color:#00a65a}.form-group.has-warning label{color:#f39c12}.form-group.has-warning .form-control,.form-group.has-warning .input-group-addon{border-color:#f39c12;box-shadow:none}.form-group.has-warning .help-block{color:#f39c12}.form-group.has-error label{color:#dd4b39}.form-group.has-error .form-control,.form-group.has-error .input-group-addon{border-color:#dd4b39;box-shadow:none}.form-group.has-error .help-block{color:#dd4b39}.input-group .input-group-addon{border-radius:0;border-color:#d2d6de;background-color:#fff}.btn-group-vertical .btn.btn-flat:first-of-type,.btn-group-vertical .btn.btn-flat:last-of-type{border-radius:0}.icheck>label{padding-left:0}.form-control-feedback.fa{line-height:34px}.input-lg+.form-control-feedback.fa,.input-group-lg+.form-control-feedback.fa,.form-group-lg .form-control+.form-control-feedback.fa{line-height:46px}.input-sm+.form-control-feedback.fa,.input-group-sm+.form-control-feedback.fa,.form-group-sm .form-control+.form-control-feedback.fa{line-height:30px}.progress,.progress>.progress-bar{-webkit-box-shadow:none;box-shadow:none}.progress,.progress>.progress-bar,.progress .progress-bar,.progress>.progress-bar .progress-bar{border-radius:1px}.progress.sm,.progress-sm{height:10px}.progress.sm,.progress-sm,.progress.sm .progress-bar,.progress-sm .progress-bar{border-radius:1px}.progress.xs,.progress-xs{height:7px}.progress.xs,.progress-xs,.progress.xs .progress-bar,.progress-xs .progress-bar{border-radius:1px}.progress.xxs,.progress-xxs{height:3px}.progress.xxs,.progress-xxs,.progress.xxs .progress-bar,.progress-xxs .progress-bar{border-radius:1px}.progress.vertical{position:relative;width:30px;height:200px;display:inline-block;margin-right:10px}.progress.vertical>.progress-bar{width:100%;position:absolute;bottom:0}.progress.vertical.sm,.progress.vertical.progress-sm{width:20px}.progress.vertical.xs,.progress.vertical.progress-xs{width:10px}.progress.vertical.xxs,.progress.vertical.progress-xxs{width:3px}.progress-group .progress-text{font-weight:600}.progress-group .progress-number{float:right}.table tr>td .progress{margin:0}.progress-bar-light-blue,.progress-bar-primary{background-color:#3c8dbc}.progress-striped .progress-bar-light-blue,.progress-striped .progress-bar-primary{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-green,.progress-bar-success{background-color:#00a65a}.progress-striped .progress-bar-green,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-aqua,.progress-bar-info{background-color:#00c0ef}.progress-striped .progress-bar-aqua,.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-yellow,.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-yellow,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-red,.progress-bar-danger{background-color:#dd4b39}.progress-striped .progress-bar-red,.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.small-box{border-radius:2px;position:relative;display:block;margin-bottom:20px;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.small-box>.inner{padding:10px}.small-box>.small-box-footer{position:relative;text-align:center;padding:3px 0;color:#fff;color:rgba(255,255,255,0.8);display:block;z-index:10;background:rgba(0,0,0,0.1);text-decoration:none}.small-box>.small-box-footer:hover{color:#fff;background:rgba(0,0,0,0.15)}.small-box h3{font-size:38px;font-weight:bold;margin:0 0 10px 0;white-space:nowrap;padding:0}.small-box p{font-size:15px}.small-box p>small{display:block;color:#f9f9f9;font-size:13px;margin-top:5px}.small-box h3,.small-box p{z-index:5}.small-box .icon{-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;position:absolute;top:-10px;right:10px;z-index:0;font-size:90px;color:rgba(0,0,0,0.15)}.small-box:hover{text-decoration:none;color:#f9f9f9}.small-box:hover .icon{font-size:95px}@media(max-width:767px){.small-box{text-align:center}.small-box .icon{display:none}.small-box p{font-size:12px}}.box{position:relative;border-radius:3px;background:#fff;border-top:3px solid #d2d6de;margin-bottom:20px;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.box.box-primary{border-top-color:#3c8dbc}.box.box-info{border-top-color:#00c0ef}.box.box-danger{border-top-color:#dd4b39}.box.box-warning{border-top-color:#f39c12}.box.box-success{border-top-color:#00a65a}.box.box-default{border-top-color:#d2d6de}.box.collapsed-box .box-body,.box.collapsed-box .box-footer{display:none}.box .nav-stacked>li{border-bottom:1px solid #f4f4f4;margin:0}.box .nav-stacked>li:last-of-type{border-bottom:0}.box.height-control .box-body{max-height:300px;overflow:auto}.box .border-right{border-right:1px solid #f4f4f4}.box .border-left{border-left:1px solid #f4f4f4}.box.box-solid{border-top:0}.box.box-solid>.box-header .btn.btn-default{background:transparent}.box.box-solid>.box-header .btn:hover,.box.box-solid>.box-header a:hover{background:rgba(0,0,0,0.1)}.box.box-solid.box-default{border:1px solid #d2d6de}.box.box-solid.box-default>.box-header{color:#444;background:#d2d6de;background-color:#d2d6de}.box.box-solid.box-default>.box-header a,.box.box-solid.box-default>.box-header .btn{color:#444}.box.box-solid.box-primary{border:1px solid #3c8dbc}.box.box-solid.box-primary>.box-header{color:#fff;background:#3c8dbc;background-color:#3c8dbc}.box.box-solid.box-primary>.box-header a,.box.box-solid.box-primary>.box-header .btn{color:#fff}.box.box-solid.box-info{border:1px solid #00c0ef}.box.box-solid.box-info>.box-header{color:#fff;background:#00c0ef;background-color:#00c0ef}.box.box-solid.box-info>.box-header a,.box.box-solid.box-info>.box-header .btn{color:#fff}.box.box-solid.box-danger{border:1px solid #dd4b39}.box.box-solid.box-danger>.box-header{color:#fff;background:#dd4b39;background-color:#dd4b39}.box.box-solid.box-danger>.box-header a,.box.box-solid.box-danger>.box-header .btn{color:#fff}.box.box-solid.box-warning{border:1px solid #f39c12}.box.box-solid.box-warning>.box-header{color:#fff;background:#f39c12;background-color:#f39c12}.box.box-solid.box-warning>.box-header a,.box.box-solid.box-warning>.box-header .btn{color:#fff}.box.box-solid.box-success{border:1px solid #00a65a}.box.box-solid.box-success>.box-header{color:#fff;background:#00a65a;background-color:#00a65a}.box.box-solid.box-success>.box-header a,.box.box-solid.box-success>.box-header .btn{color:#fff}.box.box-solid>.box-header>.box-tools .btn{border:0;box-shadow:none}.box.box-solid[class*='bg']>.box-header{color:#fff}.box .box-group>.box{margin-bottom:5px}.box .knob-label{text-align:center;color:#333;font-weight:100;font-size:12px;margin-bottom:.3em}.box>.overlay,.overlay-wrapper>.overlay,.box>.loading-img,.overlay-wrapper>.loading-img{position:absolute;top:0;left:0;width:100%;height:100%}.box .overlay,.overlay-wrapper .overlay{z-index:50;background:rgba(255,255,255,0.7);border-radius:3px}.box .overlay>.fa,.overlay-wrapper .overlay>.fa{position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-15px;color:#000;font-size:30px}.box .overlay.dark,.overlay-wrapper .overlay.dark{background:rgba(0,0,0,0.5)}.box-header:before,.box-body:before,.box-footer:before,.box-header:after,.box-body:after,.box-footer:after{content:" ";display:table}.box-header:after,.box-body:after,.box-footer:after{clear:both}.box-header{color:#444;display:block;padding:10px;position:relative}.box-header.with-border{border-bottom:1px solid #f4f4f4}.collapsed-box .box-header.with-border{border-bottom:0}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion,.box-header .box-title{display:inline-block;font-size:18px;margin:0;line-height:1}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion{margin-right:5px}.box-header>.box-tools{position:absolute;right:10px;top:5px}.box-header>.box-tools [data-toggle="tooltip"]{position:relative}.box-header>.box-tools.pull-right .dropdown-menu{right:0;left:auto}.btn-box-tool{padding:5px;font-size:12px;background:transparent;color:#97a0b3}.open .btn-box-tool,.btn-box-tool:hover{color:#606c84}.btn-box-tool.btn:active{box-shadow:none}.box-body{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;padding:10px}.no-header .box-body{border-top-right-radius:3px;border-top-left-radius:3px}.box-body>.table{margin-bottom:0}.box-body .fc{margin-top:5px}.box-body .full-width-chart{margin:-19px}.box-body.no-padding .full-width-chart{margin:-9px}.box-body .box-pane{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px}.box-body .box-pane-right{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:0}.box-footer{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border-top:1px solid #f4f4f4;padding:10px;background-color:#fff}.chart-legend{margin:10px 0}@media(max-width:991px){.chart-legend>li{float:left;margin-right:10px}}.box-comments{background:#f7f7f7}.box-comments .box-comment{padding:8px 0;border-bottom:1px solid #eee}.box-comments .box-comment:before,.box-comments .box-comment:after{content:" ";display:table}.box-comments .box-comment:after{clear:both}.box-comments .box-comment:last-of-type{border-bottom:0}.box-comments .box-comment:first-of-type{padding-top:0}.box-comments .box-comment img{float:left}.box-comments .comment-text{margin-left:40px;color:#555}.box-comments .username{color:#444;display:block;font-weight:600}.box-comments .text-muted{font-weight:400;font-size:12px}.todo-list{margin:0;padding:0;list-style:none;overflow:auto}.todo-list>li{border-radius:2px;padding:10px;background:#f4f4f4;margin-bottom:2px;border-left:2px solid #e6e7e8;color:#444}.todo-list>li:last-of-type{margin-bottom:0}.todo-list>li>input[type='checkbox']{margin:0 10px 0 5px}.todo-list>li .text{display:inline-block;margin-left:5px;font-weight:600}.todo-list>li .label{margin-left:10px;font-size:9px}.todo-list>li .tools{display:none;float:right;color:#dd4b39}.todo-list>li .tools>.fa,.todo-list>li .tools>.glyphicon,.todo-list>li .tools>.ion{margin-right:5px;cursor:pointer}.todo-list>li:hover .tools{display:inline-block}.todo-list>li.done{color:#999}.todo-list>li.done .text{text-decoration:line-through;font-weight:500}.todo-list>li.done .label{background:#d2d6de !important}.todo-list .danger{border-left-color:#dd4b39}.todo-list .warning{border-left-color:#f39c12}.todo-list .info{border-left-color:#00c0ef}.todo-list .success{border-left-color:#00a65a}.todo-list .primary{border-left-color:#3c8dbc}.todo-list .handle{display:inline-block;cursor:move;margin:0 5px}.chat{padding:5px 20px 5px 10px}.chat .item{margin-bottom:10px}.chat .item:before,.chat .item:after{content:" ";display:table}.chat .item:after{clear:both}.chat .item>img{width:40px;height:40px;border:2px solid transparent;border-radius:50%}.chat .item>.online{border:2px solid #00a65a}.chat .item>.offline{border:2px solid #dd4b39}.chat .item>.message{margin-left:55px;margin-top:-40px}.chat .item>.message>.name{display:block;font-weight:600}.chat .item>.attachment{border-radius:3px;background:#f4f4f4;margin-left:65px;margin-right:15px;padding:10px}.chat .item>.attachment>h4{margin:0 0 5px 0;font-weight:600;font-size:14px}.chat .item>.attachment>p,.chat .item>.attachment>.filename{font-weight:600;font-size:13px;font-style:italic;margin:0}.chat .item>.attachment:before,.chat .item>.attachment:after{content:" ";display:table}.chat .item>.attachment:after{clear:both}.box-input{max-width:200px}.modal .panel-body{color:#444}.info-box{display:block;min-height:90px;background:#fff;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:2px;margin-bottom:15px}.info-box small{font-size:14px}.info-box .progress{background:rgba(0,0,0,0.2);margin:5px -10px 5px -10px;height:2px}.info-box .progress,.info-box .progress .progress-bar{border-radius:0}.info-box .progress .progress-bar{background:#fff}.info-box-icon{border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px;display:block;float:left;height:90px;width:90px;text-align:center;font-size:45px;line-height:90px;background:rgba(0,0,0,0.2)}.info-box-icon>img{max-width:100%}.info-box-content{padding:5px 10px;margin-left:90px}.info-box-number{display:block;font-weight:bold;font-size:18px}.progress-description,.info-box-text{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.info-box-text{text-transform:uppercase}.info-box-more{display:block}.progress-description{margin:0}.timeline{position:relative;margin:0 0 30px 0;padding:0;list-style:none}.timeline:before{content:'';position:absolute;top:0;bottom:0;width:4px;background:#ddd;left:31px;margin:0;border-radius:2px}.timeline>li{position:relative;margin-right:10px;margin-bottom:15px}.timeline>li:before,.timeline>li:after{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li>.timeline-item{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;margin-top:0;background:#fff;color:#444;margin-left:60px;margin-right:15px;padding:0;position:relative}.timeline>li>.timeline-item>.time{color:#999;float:right;padding:10px;font-size:12px}.timeline>li>.timeline-item>.timeline-header{margin:0;color:#555;border-bottom:1px solid #f4f4f4;padding:10px;font-size:16px;line-height:1.1}.timeline>li>.timeline-item>.timeline-header>a{font-weight:600}.timeline>li>.timeline-item>.timeline-body,.timeline>li>.timeline-item>.timeline-footer{padding:10px}.timeline>li>.fa,.timeline>li>.glyphicon,.timeline>li>.ion{width:30px;height:30px;font-size:15px;line-height:30px;position:absolute;color:#666;background:#d2d6de;border-radius:50%;text-align:center;left:18px;top:0}.timeline>.time-label>span{font-weight:600;padding:5px;display:inline-block;background-color:#fff;border-radius:4px}.timeline-inverse>li>.timeline-item{background:#f0f0f0;border:1px solid #ddd;-webkit-box-shadow:none;box-shadow:none}.timeline-inverse>li>.timeline-item>.timeline-header{border-bottom-color:#ddd}.btn{border-radius:3px;-webkit-box-shadow:none;box-shadow:none;border:1px solid transparent}.btn.uppercase{text-transform:uppercase}.btn.btn-flat{border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border-width:1px}.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:focus{outline:0}.btn.btn-file{position:relative;overflow:hidden}.btn.btn-file>input[type='file']{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;opacity:0;filter:alpha(opacity=0);outline:0;background:white;cursor:inherit;display:block}.btn-default{background-color:#f4f4f4;color:#444;border-color:#ddd}.btn-default:hover,.btn-default:active,.btn-default.hover{background-color:#e7e7e7}.btn-primary{background-color:#3c8dbc;border-color:#367fa9}.btn-primary:hover,.btn-primary:active,.btn-primary.hover{background-color:#367fa9}.btn-success{background-color:#00a65a;border-color:#008d4c}.btn-success:hover,.btn-success:active,.btn-success.hover{background-color:#008d4c}.btn-info{background-color:#00c0ef;border-color:#00acd6}.btn-info:hover,.btn-info:active,.btn-info.hover{background-color:#00acd6}.btn-danger{background-color:#dd4b39;border-color:#d73925}.btn-danger:hover,.btn-danger:active,.btn-danger.hover{background-color:#d73925}.btn-warning{background-color:#f39c12;border-color:#e08e0b}.btn-warning:hover,.btn-warning:active,.btn-warning.hover{background-color:#e08e0b}.btn-outline{border:1px solid #fff;background:transparent;color:#fff}.btn-outline:hover,.btn-outline:focus,.btn-outline:active{color:rgba(255,255,255,0.7);border-color:rgba(255,255,255,0.7)}.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn[class*='bg-']:hover{-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,0.2);box-shadow:inset 0 0 100px rgba(0,0,0,0.2)}.btn-app{border-radius:3px;position:relative;padding:15px 5px;margin:0 0 10px 10px;min-width:80px;height:60px;text-align:center;color:#666;border:1px solid #ddd;background-color:#f4f4f4;font-size:12px}.btn-app>.fa,.btn-app>.glyphicon,.btn-app>.ion{font-size:20px;display:block}.btn-app:hover{background:#f4f4f4;color:#444;border-color:#aaa}.btn-app:active,.btn-app:focus{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-app>.badge{position:absolute;top:-3px;right:-10px;font-size:10px;font-weight:400}.callout{border-radius:3px;margin:0 0 20px 0;padding:15px 30px 15px 15px;border-left:5px solid #eee}.callout a{color:#fff;text-decoration:underline}.callout a:hover{color:#eee}.callout h4{margin-top:0;font-weight:600}.callout p:last-child{margin-bottom:0}.callout code,.callout .highlight{background-color:#fff}.callout.callout-danger{border-color:#c23321}.callout.callout-warning{border-color:#c87f0a}.callout.callout-info{border-color:#0097bc}.callout.callout-success{border-color:#00733e}.alert{border-radius:3px}.alert h4{font-weight:600}.alert .icon{margin-right:10px}.alert .close{color:#000;opacity:.2;filter:alpha(opacity=20)}.alert .close:hover{opacity:.5;filter:alpha(opacity=50)}.alert a{color:#fff;text-decoration:underline}.alert-success{border-color:#008d4c}.alert-danger,.alert-error{border-color:#d73925}.alert-warning{border-color:#e08e0b}.alert-info{border-color:#00acd6}.nav>li>a:hover,.nav>li>a:active,.nav>li>a:focus{color:#444;background:#f7f7f7}.nav-pills>li>a{border-radius:0;border-top:3px solid transparent;color:#444}.nav-pills>li>a>.fa,.nav-pills>li>a>.glyphicon,.nav-pills>li>a>.ion{margin-right:5px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{border-top-color:#3c8dbc}.nav-pills>li.active>a{font-weight:600}.nav-stacked>li>a{border-radius:0;border-top:0;border-left:3px solid transparent;color:#444}.nav-stacked>li.active>a,.nav-stacked>li.active>a:hover{background:transparent;color:#444;border-top:0;border-left-color:#3c8dbc}.nav-stacked>li.header{border-bottom:1px solid #ddd;color:#777;margin-bottom:10px;padding:5px 10px;text-transform:uppercase}.nav-tabs-custom{margin-bottom:20px;background:#fff;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px}.nav-tabs-custom>.nav-tabs{margin:0;border-bottom-color:#f4f4f4;border-top-right-radius:3px;border-top-left-radius:3px}.nav-tabs-custom>.nav-tabs>li{border-top:3px solid transparent;margin-bottom:-2px;margin-right:5px}.nav-tabs-custom>.nav-tabs>li>a{color:#444;border-radius:0}.nav-tabs-custom>.nav-tabs>li>a.text-muted{color:#999}.nav-tabs-custom>.nav-tabs>li>a,.nav-tabs-custom>.nav-tabs>li>a:hover{background:transparent;margin:0}.nav-tabs-custom>.nav-tabs>li>a:hover{color:#999}.nav-tabs-custom>.nav-tabs>li:not(.active)>a:hover,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:focus,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:active{border-color:transparent}.nav-tabs-custom>.nav-tabs>li.active{border-top-color:#3c8dbc}.nav-tabs-custom>.nav-tabs>li.active>a,.nav-tabs-custom>.nav-tabs>li.active:hover>a{background-color:#fff;color:#444}.nav-tabs-custom>.nav-tabs>li.active>a{border-top-color:transparent;border-left-color:#f4f4f4;border-right-color:#f4f4f4}.nav-tabs-custom>.nav-tabs>li:first-of-type{margin-left:0}.nav-tabs-custom>.nav-tabs>li:first-of-type.active>a{border-left-color:transparent}.nav-tabs-custom>.nav-tabs.pull-right{float:none !important}.nav-tabs-custom>.nav-tabs.pull-right>li{float:right}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type{margin-right:0}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type>a{border-left-width:1px}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type.active>a{border-left-color:#f4f4f4;border-right-color:transparent}.nav-tabs-custom>.nav-tabs>li.header{line-height:35px;padding:0 10px;font-size:20px;color:#444}.nav-tabs-custom>.nav-tabs>li.header>.fa,.nav-tabs-custom>.nav-tabs>li.header>.glyphicon,.nav-tabs-custom>.nav-tabs>li.header>.ion{margin-right:5px}.nav-tabs-custom>.tab-content{background:#fff;padding:10px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.nav-tabs-custom .dropdown.open>a:active,.nav-tabs-custom .dropdown.open>a:focus{background:transparent;color:#999}.nav-tabs-custom.tab-primary>.nav-tabs>li.active{border-top-color:#3c8dbc}.nav-tabs-custom.tab-info>.nav-tabs>li.active{border-top-color:#00c0ef}.nav-tabs-custom.tab-danger>.nav-tabs>li.active{border-top-color:#dd4b39}.nav-tabs-custom.tab-warning>.nav-tabs>li.active{border-top-color:#f39c12}.nav-tabs-custom.tab-success>.nav-tabs>li.active{border-top-color:#00a65a}.nav-tabs-custom.tab-default>.nav-tabs>li.active{border-top-color:#d2d6de}.pagination>li>a{background:#fafafa;color:#666}.pagination.pagination-flat>li>a{border-radius:0 !important}.products-list{list-style:none;margin:0;padding:0}.products-list>.item{border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);padding:10px 0;background:#fff}.products-list>.item:before,.products-list>.item:after{content:" ";display:table}.products-list>.item:after{clear:both}.products-list .product-img{float:left}.products-list .product-img img{width:50px;height:50px}.products-list .product-info{margin-left:60px}.products-list .product-title{font-weight:600}.products-list .product-description{display:block;color:#999;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.product-list-in-box>.item{-webkit-box-shadow:none;box-shadow:none;border-radius:0;border-bottom:1px solid #f4f4f4}.product-list-in-box>.item:last-of-type{border-bottom-width:0}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{border-top:1px solid #f4f4f4}.table>thead>tr>th{border-bottom:2px solid #f4f4f4}.table tr td .progress{margin-top:5px}.table-bordered{border:1px solid #f4f4f4}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #f4f4f4}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table.no-border,.table.no-border td,.table.no-border th{border:0}table.text-center,table.text-center td,table.text-center th{text-align:center}.table.align th{text-align:left}.table.align td{text-align:right}.label-default{background-color:#d2d6de;color:#444}.direct-chat .box-body{border-bottom-right-radius:0;border-bottom-left-radius:0;position:relative;overflow-x:hidden;padding:0}.direct-chat.chat-pane-open .direct-chat-contacts{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.direct-chat-messages{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0);padding:10px;height:250px;overflow:auto}.direct-chat-msg,.direct-chat-text{display:block}.direct-chat-msg{margin-bottom:10px}.direct-chat-msg:before,.direct-chat-msg:after{content:" ";display:table}.direct-chat-msg:after{clear:both}.direct-chat-messages,.direct-chat-contacts{-webkit-transition:-webkit-transform .5s ease-in-out;-moz-transition:-moz-transform .5s ease-in-out;-o-transition:-o-transform .5s ease-in-out;transition:transform .5s ease-in-out}.direct-chat-text{border-radius:5px;position:relative;padding:5px 10px;background:#d2d6de;border:1px solid #d2d6de;margin:5px 0 0 50px;color:#444}.direct-chat-text:after,.direct-chat-text:before{position:absolute;right:100%;top:15px;border:solid transparent;border-right-color:#d2d6de;content:' ';height:0;width:0;pointer-events:none}.direct-chat-text:after{border-width:5px;margin-top:-5px}.direct-chat-text:before{border-width:6px;margin-top:-6px}.right .direct-chat-text{margin-right:50px;margin-left:0}.right .direct-chat-text:after,.right .direct-chat-text:before{right:auto;left:100%;border-right-color:transparent;border-left-color:#d2d6de}.direct-chat-img{border-radius:50%;float:left;width:40px;height:40px}.right .direct-chat-img{float:right}.direct-chat-info{display:block;margin-bottom:2px;font-size:12px}.direct-chat-name{font-weight:600}.direct-chat-timestamp{color:#999}.direct-chat-contacts-open .direct-chat-contacts{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.direct-chat-contacts{-webkit-transform:translate(101%,0);-ms-transform:translate(101%,0);-o-transform:translate(101%,0);transform:translate(101%,0);position:absolute;top:0;bottom:0;height:250px;width:100%;background:#222d32;color:#fff;overflow:auto}.contacts-list>li{border-bottom:1px solid rgba(0,0,0,0.2);padding:10px;margin:0}.contacts-list>li:before,.contacts-list>li:after{content:" ";display:table}.contacts-list>li:after{clear:both}.contacts-list>li:last-of-type{border-bottom:0}.contacts-list-img{border-radius:50%;width:40px;float:left}.contacts-list-info{margin-left:45px;color:#fff}.contacts-list-name,.contacts-list-status{display:block}.contacts-list-name{font-weight:600}.contacts-list-status{font-size:12px}.contacts-list-date{color:#aaa;font-weight:normal}.contacts-list-msg{color:#999}.direct-chat-danger .right>.direct-chat-text{background:#dd4b39;border-color:#dd4b39;color:#fff}.direct-chat-danger .right>.direct-chat-text:after,.direct-chat-danger .right>.direct-chat-text:before{border-left-color:#dd4b39}.direct-chat-primary .right>.direct-chat-text{background:#3c8dbc;border-color:#3c8dbc;color:#fff}.direct-chat-primary .right>.direct-chat-text:after,.direct-chat-primary .right>.direct-chat-text:before{border-left-color:#3c8dbc}.direct-chat-warning .right>.direct-chat-text{background:#f39c12;border-color:#f39c12;color:#fff}.direct-chat-warning .right>.direct-chat-text:after,.direct-chat-warning .right>.direct-chat-text:before{border-left-color:#f39c12}.direct-chat-info .right>.direct-chat-text{background:#00c0ef;border-color:#00c0ef;color:#fff}.direct-chat-info .right>.direct-chat-text:after,.direct-chat-info .right>.direct-chat-text:before{border-left-color:#00c0ef}.direct-chat-success .right>.direct-chat-text{background:#00a65a;border-color:#00a65a;color:#fff}.direct-chat-success .right>.direct-chat-text:after,.direct-chat-success .right>.direct-chat-text:before{border-left-color:#00a65a}.users-list>li{width:25%;float:left;padding:10px;text-align:center}.users-list>li img{border-radius:50%;max-width:100%;height:auto}.users-list>li>a:hover,.users-list>li>a:hover .users-list-name{color:#999}.users-list-name,.users-list-date{display:block}.users-list-name{font-weight:600;color:#444;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.users-list-date{color:#999;font-size:12px}.carousel-control.left,.carousel-control.right{background-image:none}.carousel-control>.fa{font-size:40px;position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-20px}.modal{background:rgba(0,0,0,0.3)}.modal-content{border-radius:0;-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125);border:0}@media(min-width:768px){.modal-content{-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125)}}.modal-header{border-bottom-color:#f4f4f4}.modal-footer{border-top-color:#f4f4f4}.modal-primary .modal-header,.modal-primary .modal-footer{border-color:#307095}.modal-warning .modal-header,.modal-warning .modal-footer{border-color:#c87f0a}.modal-info .modal-header,.modal-info .modal-footer{border-color:#0097bc}.modal-success .modal-header,.modal-success .modal-footer{border-color:#00733e}.modal-danger .modal-header,.modal-danger .modal-footer{border-color:#c23321}.box-widget{border:0;position:relative}.widget-user .widget-user-header{padding:20px;height:120px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user .widget-user-username{margin-top:0;margin-bottom:5px;font-size:25px;font-weight:300;text-shadow:0 1px 1px rgba(0,0,0,0.2)}.widget-user .widget-user-desc{margin-top:0}.widget-user .widget-user-image{position:absolute;top:65px;left:50%;margin-left:-45px}.widget-user .widget-user-image>img{width:90px;height:auto;border:3px solid #fff}.widget-user .box-footer{padding-top:30px}.widget-user-2 .widget-user-header{padding:20px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user-2 .widget-user-username{margin-top:5px;margin-bottom:5px;font-size:25px;font-weight:300}.widget-user-2 .widget-user-desc{margin-top:0}.widget-user-2 .widget-user-username,.widget-user-2 .widget-user-desc{margin-left:75px}.widget-user-2 .widget-user-image>img{width:65px;height:auto;float:left}.mailbox-messages>.table{margin:0}.mailbox-controls{padding:5px}.mailbox-controls.with-border{border-bottom:1px solid #f4f4f4}.mailbox-read-info{border-bottom:1px solid #f4f4f4;padding:10px}.mailbox-read-info h3{font-size:20px;margin:0}.mailbox-read-info h5{margin:0;padding:5px 0 0 0}.mailbox-read-time{color:#999;font-size:13px}.mailbox-read-message{padding:10px}.mailbox-attachments li{float:left;width:200px;border:1px solid #eee;margin-bottom:10px;margin-right:10px}.mailbox-attachment-name{font-weight:bold;color:#666}.mailbox-attachment-icon,.mailbox-attachment-info,.mailbox-attachment-size{display:block}.mailbox-attachment-info{padding:10px;background:#f4f4f4}.mailbox-attachment-size{color:#999;font-size:12px}.mailbox-attachment-icon{text-align:center;font-size:65px;color:#666;padding:20px 10px}.mailbox-attachment-icon.has-img{padding:0}.mailbox-attachment-icon.has-img>img{max-width:100%;height:auto}.lockscreen{background:#d2d6de}.lockscreen-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.lockscreen-logo a{color:#444}.lockscreen-wrapper{max-width:400px;margin:0 auto;margin-top:10%}.lockscreen .lockscreen-name{text-align:center;font-weight:600}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image>img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:10px}.login-logo,.register-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.login-logo a,.register-logo a{color:#444}.login-page,.register-page{background:#d2d6de}.login-box,.register-box{width:360px;margin:7% auto}@media(max-width:768px){.login-box,.register-box{width:90%;margin-top:20px}}.login-box-body,.register-box-body{background:#fff;padding:20px;border-top:0;color:#666}.login-box-body .form-control-feedback,.register-box-body .form-control-feedback{color:#777}.login-box-msg,.register-box-msg{margin:0;text-align:center;padding:0 20px 20px 20px}.social-auth-links{margin:10px 0}.error-page{width:600px;margin:20px auto 0 auto}@media(max-width:991px){.error-page{width:100%}}.error-page>.headline{float:left;font-size:100px;font-weight:300}@media(max-width:991px){.error-page>.headline{float:none;text-align:center}}.error-page>.error-content{margin-left:190px;display:block}@media(max-width:991px){.error-page>.error-content{margin-left:0}}.error-page>.error-content>h3{font-weight:300;font-size:25px}@media(max-width:991px){.error-page>.error-content>h3{text-align:center}}.invoice{position:relative;background:#fff;border:1px solid #f4f4f4;padding:20px;margin:10px 25px}.invoice-title{margin-top:0}.profile-user-img{margin:0 auto;width:100px;padding:3px;border:3px solid #d2d6de}.profile-username{font-size:21px;margin-top:5px}.post{border-bottom:1px solid #d2d6de;margin-bottom:15px;padding-bottom:15px;color:#666}.post:last-of-type{border-bottom:0;margin-bottom:0;padding-bottom:0}.post .user-block{margin-bottom:15px}.btn-social{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-social>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social.btn-lg{padding-left:61px}.btn-social.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social.btn-sm{padding-left:38px}.btn-social.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social.btn-xs{padding-left:30px}.btn-social.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:34px;width:34px;padding:0}.btn-social-icon>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social-icon.btn-lg{padding-left:61px}.btn-social-icon.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social-icon.btn-sm{padding-left:38px}.btn-social-icon.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social-icon.btn-xs{padding-left:30px}.btn-social-icon.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon>:first-child{border:0;text-align:center;width:100%}.btn-social-icon.btn-lg{height:45px;width:45px;padding-left:0;padding-right:0}.btn-social-icon.btn-sm{height:30px;width:30px;padding-left:0;padding-right:0}.btn-social-icon.btn-xs{height:22px;width:22px;padding-left:0;padding-right:0}.btn-adn{color:#fff;background-color:#d87a68;border-color:rgba(0,0,0,0.2)}.btn-adn:focus,.btn-adn.focus{color:#fff;background-color:#ce563f;border-color:rgba(0,0,0,0.2)}.btn-adn:hover{color:#fff;background-color:#ce563f;border-color:rgba(0,0,0,0.2)}.btn-adn:active,.btn-adn.active,.open>.dropdown-toggle.btn-adn{color:#fff;background-color:#ce563f;border-color:rgba(0,0,0,0.2)}.btn-adn:active,.btn-adn.active,.open>.dropdown-toggle.btn-adn{background-image:none}.btn-adn .badge{color:#d87a68;background-color:#fff}.btn-bitbucket{color:#fff;background-color:#205081;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:focus,.btn-bitbucket.focus{color:#fff;background-color:#163758;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:hover{color:#fff;background-color:#163758;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:active,.btn-bitbucket.active,.open>.dropdown-toggle.btn-bitbucket{color:#fff;background-color:#163758;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:active,.btn-bitbucket.active,.open>.dropdown-toggle.btn-bitbucket{background-image:none}.btn-bitbucket .badge{color:#205081;background-color:#fff}.btn-dropbox{color:#fff;background-color:#1087dd;border-color:rgba(0,0,0,0.2)}.btn-dropbox:focus,.btn-dropbox.focus{color:#fff;background-color:#0d6aad;border-color:rgba(0,0,0,0.2)}.btn-dropbox:hover{color:#fff;background-color:#0d6aad;border-color:rgba(0,0,0,0.2)}.btn-dropbox:active,.btn-dropbox.active,.open>.dropdown-toggle.btn-dropbox{color:#fff;background-color:#0d6aad;border-color:rgba(0,0,0,0.2)}.btn-dropbox:active,.btn-dropbox.active,.open>.dropdown-toggle.btn-dropbox{background-image:none}.btn-dropbox .badge{color:#1087dd;background-color:#fff}.btn-facebook{color:#fff;background-color:#3b5998;border-color:rgba(0,0,0,0.2)}.btn-facebook:focus,.btn-facebook.focus{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:hover{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{background-image:none}.btn-facebook .badge{color:#3b5998;background-color:#fff}.btn-flickr{color:#fff;background-color:#ff0084;border-color:rgba(0,0,0,0.2)}.btn-flickr:focus,.btn-flickr.focus{color:#fff;background-color:#cc006a;border-color:rgba(0,0,0,0.2)}.btn-flickr:hover{color:#fff;background-color:#cc006a;border-color:rgba(0,0,0,0.2)}.btn-flickr:active,.btn-flickr.active,.open>.dropdown-toggle.btn-flickr{color:#fff;background-color:#cc006a;border-color:rgba(0,0,0,0.2)}.btn-flickr:active,.btn-flickr.active,.open>.dropdown-toggle.btn-flickr{background-image:none}.btn-flickr .badge{color:#ff0084;background-color:#fff}.btn-foursquare{color:#fff;background-color:#f94877;border-color:rgba(0,0,0,0.2)}.btn-foursquare:focus,.btn-foursquare.focus{color:#fff;background-color:#f71752;border-color:rgba(0,0,0,0.2)}.btn-foursquare:hover{color:#fff;background-color:#f71752;border-color:rgba(0,0,0,0.2)}.btn-foursquare:active,.btn-foursquare.active,.open>.dropdown-toggle.btn-foursquare{color:#fff;background-color:#f71752;border-color:rgba(0,0,0,0.2)}.btn-foursquare:active,.btn-foursquare.active,.open>.dropdown-toggle.btn-foursquare{background-image:none}.btn-foursquare .badge{color:#f94877;background-color:#fff}.btn-github{color:#fff;background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-github:focus,.btn-github.focus{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:hover{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{background-image:none}.btn-github .badge{color:#444;background-color:#fff}.btn-google{color:#fff;background-color:#dd4b39;border-color:rgba(0,0,0,0.2)}.btn-google:focus,.btn-google.focus{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:hover{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{background-image:none}.btn-google .badge{color:#dd4b39;background-color:#fff}.btn-instagram{color:#fff;background-color:#3f729b;border-color:rgba(0,0,0,0.2)}.btn-instagram:focus,.btn-instagram.focus{color:#fff;background-color:#305777;border-color:rgba(0,0,0,0.2)}.btn-instagram:hover{color:#fff;background-color:#305777;border-color:rgba(0,0,0,0.2)}.btn-instagram:active,.btn-instagram.active,.open>.dropdown-toggle.btn-instagram{color:#fff;background-color:#305777;border-color:rgba(0,0,0,0.2)}.btn-instagram:active,.btn-instagram.active,.open>.dropdown-toggle.btn-instagram{background-image:none}.btn-instagram .badge{color:#3f729b;background-color:#fff}.btn-linkedin{color:#fff;background-color:#007bb6;border-color:rgba(0,0,0,0.2)}.btn-linkedin:focus,.btn-linkedin.focus{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:hover{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{background-image:none}.btn-linkedin .badge{color:#007bb6;background-color:#fff}.btn-microsoft{color:#fff;background-color:#2672ec;border-color:rgba(0,0,0,0.2)}.btn-microsoft:focus,.btn-microsoft.focus{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:hover{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{background-image:none}.btn-microsoft .badge{color:#2672ec;background-color:#fff}.btn-openid{color:#fff;background-color:#f7931e;border-color:rgba(0,0,0,0.2)}.btn-openid:focus,.btn-openid.focus{color:#fff;background-color:#da7908;border-color:rgba(0,0,0,0.2)}.btn-openid:hover{color:#fff;background-color:#da7908;border-color:rgba(0,0,0,0.2)}.btn-openid:active,.btn-openid.active,.open>.dropdown-toggle.btn-openid{color:#fff;background-color:#da7908;border-color:rgba(0,0,0,0.2)}.btn-openid:active,.btn-openid.active,.open>.dropdown-toggle.btn-openid{background-image:none}.btn-openid .badge{color:#f7931e;background-color:#fff}.btn-pinterest{color:#fff;background-color:#cb2027;border-color:rgba(0,0,0,0.2)}.btn-pinterest:focus,.btn-pinterest.focus{color:#fff;background-color:#9f191f;border-color:rgba(0,0,0,0.2)}.btn-pinterest:hover{color:#fff;background-color:#9f191f;border-color:rgba(0,0,0,0.2)}.btn-pinterest:active,.btn-pinterest.active,.open>.dropdown-toggle.btn-pinterest{color:#fff;background-color:#9f191f;border-color:rgba(0,0,0,0.2)}.btn-pinterest:active,.btn-pinterest.active,.open>.dropdown-toggle.btn-pinterest{background-image:none}.btn-pinterest .badge{color:#cb2027;background-color:#fff}.btn-reddit{color:#000;background-color:#eff7ff;border-color:rgba(0,0,0,0.2)}.btn-reddit:focus,.btn-reddit.focus{color:#000;background-color:#bcddff;border-color:rgba(0,0,0,0.2)}.btn-reddit:hover{color:#000;background-color:#bcddff;border-color:rgba(0,0,0,0.2)}.btn-reddit:active,.btn-reddit.active,.open>.dropdown-toggle.btn-reddit{color:#000;background-color:#bcddff;border-color:rgba(0,0,0,0.2)}.btn-reddit:active,.btn-reddit.active,.open>.dropdown-toggle.btn-reddit{background-image:none}.btn-reddit .badge{color:#eff7ff;background-color:#000}.btn-soundcloud{color:#fff;background-color:#f50;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:focus,.btn-soundcloud.focus{color:#fff;background-color:#c40;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:hover{color:#fff;background-color:#c40;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:active,.btn-soundcloud.active,.open>.dropdown-toggle.btn-soundcloud{color:#fff;background-color:#c40;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:active,.btn-soundcloud.active,.open>.dropdown-toggle.btn-soundcloud{background-image:none}.btn-soundcloud .badge{color:#f50;background-color:#fff}.btn-tumblr{color:#fff;background-color:#2c4762;border-color:rgba(0,0,0,0.2)}.btn-tumblr:focus,.btn-tumblr.focus{color:#fff;background-color:#1c2d3f;border-color:rgba(0,0,0,0.2)}.btn-tumblr:hover{color:#fff;background-color:#1c2d3f;border-color:rgba(0,0,0,0.2)}.btn-tumblr:active,.btn-tumblr.active,.open>.dropdown-toggle.btn-tumblr{color:#fff;background-color:#1c2d3f;border-color:rgba(0,0,0,0.2)}.btn-tumblr:active,.btn-tumblr.active,.open>.dropdown-toggle.btn-tumblr{background-image:none}.btn-tumblr .badge{color:#2c4762;background-color:#fff}.btn-twitter{color:#fff;background-color:#55acee;border-color:rgba(0,0,0,0.2)}.btn-twitter:focus,.btn-twitter.focus{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:hover{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{background-image:none}.btn-twitter .badge{color:#55acee;background-color:#fff}.btn-vimeo{color:#fff;background-color:#1ab7ea;border-color:rgba(0,0,0,0.2)}.btn-vimeo:focus,.btn-vimeo.focus{color:#fff;background-color:#1295bf;border-color:rgba(0,0,0,0.2)}.btn-vimeo:hover{color:#fff;background-color:#1295bf;border-color:rgba(0,0,0,0.2)}.btn-vimeo:active,.btn-vimeo.active,.open>.dropdown-toggle.btn-vimeo{color:#fff;background-color:#1295bf;border-color:rgba(0,0,0,0.2)}.btn-vimeo:active,.btn-vimeo.active,.open>.dropdown-toggle.btn-vimeo{background-image:none}.btn-vimeo .badge{color:#1ab7ea;background-color:#fff}.btn-vk{color:#fff;background-color:#587ea3;border-color:rgba(0,0,0,0.2)}.btn-vk:focus,.btn-vk.focus{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:hover{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{background-image:none}.btn-vk .badge{color:#587ea3;background-color:#fff}.btn-yahoo{color:#fff;background-color:#720e9e;border-color:rgba(0,0,0,0.2)}.btn-yahoo:focus,.btn-yahoo.focus{color:#fff;background-color:#500a6f;border-color:rgba(0,0,0,0.2)}.btn-yahoo:hover{color:#fff;background-color:#500a6f;border-color:rgba(0,0,0,0.2)}.btn-yahoo:active,.btn-yahoo.active,.open>.dropdown-toggle.btn-yahoo{color:#fff;background-color:#500a6f;border-color:rgba(0,0,0,0.2)}.btn-yahoo:active,.btn-yahoo.active,.open>.dropdown-toggle.btn-yahoo{background-image:none}.btn-yahoo .badge{color:#720e9e;background-color:#fff}.fc-button{background:#f4f4f4;background-image:none;color:#444;border-color:#ddd;border-bottom-color:#ddd}.fc-button:hover,.fc-button:active,.fc-button.hover{background-color:#e9e9e9}.fc-header-title h2{font-size:15px;line-height:1.6em;color:#666;margin-left:10px}.fc-header-right{padding-right:10px}.fc-header-left{padding-left:10px}.fc-widget-header{background:#fafafa}.fc-grid{width:100%;border:0}.fc-widget-header:first-of-type,.fc-widget-content:first-of-type{border-left:0;border-right:0}.fc-widget-header:last-of-type,.fc-widget-content:last-of-type{border-right:0}.fc-toolbar{padding:10px;margin:0}.fc-day-number{font-size:20px;font-weight:300;padding-right:10px}.fc-color-picker{list-style:none;margin:0;padding:0}.fc-color-picker>li{float:left;font-size:30px;margin-right:5px;line-height:30px}.fc-color-picker>li .fa{-webkit-transition:-webkit-transform linear .3s;-moz-transition:-moz-transform linear .3s;-o-transition:-o-transform linear .3s;transition:transform linear .3s}.fc-color-picker>li .fa:hover{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);-o-transform:rotate(30deg);transform:rotate(30deg)}#add-new-event{-webkit-transition:all linear .3s;-o-transition:all linear .3s;transition:all linear .3s}.external-event{padding:5px 10px;font-weight:bold;margin-bottom:4px;box-shadow:0 1px 1px rgba(0,0,0,0.1);text-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;cursor:move}.external-event:hover{box-shadow:inset 0 0 90px rgba(0,0,0,0.2)}.select2-container--default.select2-container--focus,.select2-selection.select2-container--focus,.select2-container--default:focus,.select2-selection:focus,.select2-container--default:active,.select2-selection:active{outline:0}.select2-container--default .select2-selection--single,.select2-selection .select2-selection--single{border:1px solid #d2d6de;border-radius:0;padding:6px 12px;height:34px}.select2-container--default.select2-container--open{border-color:#3c8dbc}.select2-dropdown{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#3c8dbc;color:white}.select2-results__option{padding:6px 12px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{padding-left:0;padding-right:0;height:auto;margin-top:-4px}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:6px;padding-left:20px}.select2-container--default .select2-selection--single .select2-selection__arrow{height:28px;right:3px}.select2-container--default .select2-selection--single .select2-selection__arrow b{margin-top:0}.select2-dropdown .select2-search__field,.select2-search--inline .select2-search__field{border:1px solid #d2d6de}.select2-dropdown .select2-search__field:focus,.select2-search--inline .select2-search__field:focus{outline:0;border:1px solid #3c8dbc}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option[aria-selected=true],.select2-container--default .select2-results__option[aria-selected=true]:hover{color:#444}.select2-container--default .select2-selection--multiple{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-selection--multiple:focus{border-color:#3c8dbc}.select2-container--default.select2-container--focus .select2-selection--multiple{border-color:#d2d6de}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#3c8dbc;border-color:#367fa9;padding:1px 10px;color:#fff}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{margin-right:5px;color:rgba(255,255,255,0.7)}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#fff}.select2-container .select2-selection--single .select2-selection__rendered{padding-right:10px}.pad{padding:10px}.margin{margin:10px}.margin-bottom{margin-bottom:20px}.margin-bottom-none{margin-bottom:0}.margin-r-5{margin-right:5px}.inline{display:inline}.description-block{display:block;margin:10px 0;text-align:center}.description-block.margin-bottom{margin-bottom:25px}.description-block>.description-header{margin:0;padding:0;font-weight:600;font-size:16px}.description-block>.description-text{text-transform:uppercase}.bg-red,.bg-yellow,.bg-aqua,.bg-blue,.bg-light-blue,.bg-green,.bg-navy,.bg-teal,.bg-olive,.bg-lime,.bg-orange,.bg-fuchsia,.bg-purple,.bg-maroon,.bg-black,.bg-red-active,.bg-yellow-active,.bg-aqua-active,.bg-blue-active,.bg-light-blue-active,.bg-green-active,.bg-navy-active,.bg-teal-active,.bg-olive-active,.bg-lime-active,.bg-orange-active,.bg-fuchsia-active,.bg-purple-active,.bg-maroon-active,.bg-black-active,.callout.callout-danger,.callout.callout-warning,.callout.callout-info,.callout.callout-success,.alert-success,.alert-danger,.alert-error,.alert-warning,.alert-info,.label-danger,.label-info,.label-warning,.label-primary,.label-success,.modal-primary .modal-body,.modal-primary .modal-header,.modal-primary .modal-footer,.modal-warning .modal-body,.modal-warning .modal-header,.modal-warning .modal-footer,.modal-info .modal-body,.modal-info .modal-header,.modal-info .modal-footer,.modal-success .modal-body,.modal-success .modal-header,.modal-success .modal-footer,.modal-danger .modal-body,.modal-danger .modal-header,.modal-danger .modal-footer{color:#fff !important}.bg-gray{color:#000;background-color:#d2d6de !important}.bg-gray-light{background-color:#f7f7f7}.bg-black{background-color:#111 !important}.bg-red,.callout.callout-danger,.alert-danger,.alert-error,.label-danger,.modal-danger .modal-body{background-color:#dd4b39 !important}.bg-yellow,.callout.callout-warning,.alert-warning,.label-warning,.modal-warning .modal-body{background-color:#f39c12 !important}.bg-aqua,.callout.callout-info,.alert-info,.label-info,.modal-info .modal-body{background-color:#00c0ef !important}.bg-blue{background-color:#0073b7 !important}.bg-light-blue,.label-primary,.modal-primary .modal-body{background-color:#3c8dbc !important}.bg-green,.callout.callout-success,.alert-success,.label-success,.modal-success .modal-body{background-color:#00a65a !important}.bg-navy{background-color:#001f3f !important}.bg-teal{background-color:#39cccc !important}.bg-olive{background-color:#3d9970 !important}.bg-lime{background-color:#01ff70 !important}.bg-orange{background-color:#ff851b !important}.bg-fuchsia{background-color:#f012be !important}.bg-purple{background-color:#605ca8 !important}.bg-maroon{background-color:#d81b60 !important}.bg-gray-active{color:#000;background-color:#b5bbc8 !important}.bg-black-active{background-color:#000 !important}.bg-red-active,.modal-danger .modal-header,.modal-danger .modal-footer{background-color:#d33724 !important}.bg-yellow-active,.modal-warning .modal-header,.modal-warning .modal-footer{background-color:#db8b0b !important}.bg-aqua-active,.modal-info .modal-header,.modal-info .modal-footer{background-color:#00a7d0 !important}.bg-blue-active{background-color:#005384 !important}.bg-light-blue-active,.modal-primary .modal-header,.modal-primary .modal-footer{background-color:#357ca5 !important}.bg-green-active,.modal-success .modal-header,.modal-success .modal-footer{background-color:#008d4c !important}.bg-navy-active{background-color:#001a35 !important}.bg-teal-active{background-color:#30bbbb !important}.bg-olive-active{background-color:#368763 !important}.bg-lime-active{background-color:#00e765 !important}.bg-orange-active{background-color:#ff7701 !important}.bg-fuchsia-active{background-color:#db0ead !important}.bg-purple-active{background-color:#555299 !important}.bg-maroon-active{background-color:#ca195a !important}[class^="bg-"].disabled{opacity:.65;filter:alpha(opacity=65)}.text-red{color:#dd4b39 !important}.text-yellow{color:#f39c12 !important}.text-aqua{color:#00c0ef !important}.text-blue{color:#0073b7 !important}.text-black{color:#111 !important}.text-light-blue{color:#3c8dbc !important}.text-green{color:#00a65a !important}.text-gray{color:#d2d6de !important}.text-navy{color:#001f3f !important}.text-teal{color:#39cccc !important}.text-olive{color:#3d9970 !important}.text-lime{color:#01ff70 !important}.text-orange{color:#ff851b !important}.text-fuchsia{color:#f012be !important}.text-purple{color:#605ca8 !important}.text-maroon{color:#d81b60 !important}.link-muted{color:#7a869d}.link-muted:hover,.link-muted:focus{color:#606c84}.link-black{color:#666}.link-black:hover,.link-black:focus{color:#999}.hide{display:none !important}.no-border{border:0 !important}.no-padding{padding:0 !important}.no-margin{margin:0 !important}.no-shadow{box-shadow:none !important}.list-unstyled,.chart-legend,.contacts-list,.users-list,.mailbox-attachments{list-style:none;margin:0;padding:0}.list-group-unbordered>.list-group-item{border-left:0;border-right:0;border-radius:0;padding-left:0;padding-right:0}.flat{border-radius:0 !important}.text-bold,.text-bold.table td,.text-bold.table th{font-weight:700}.text-sm{font-size:12px}.jqstooltip{padding:5px !important;width:auto !important;height:auto !important}.bg-teal-gradient{background:#39cccc !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#39cccc),color-stop(1,#7adddd)) !important;background:-ms-linear-gradient(bottom,#39cccc,#7adddd) !important;background:-moz-linear-gradient(center bottom,#39cccc 0,#7adddd 100%) !important;background:-o-linear-gradient(#7adddd,#39cccc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#7adddd',endColorstr='#39cccc',GradientType=0) !important;color:#fff}.bg-light-blue-gradient{background:#3c8dbc !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#3c8dbc),color-stop(1,#67a8ce)) !important;background:-ms-linear-gradient(bottom,#3c8dbc,#67a8ce) !important;background:-moz-linear-gradient(center bottom,#3c8dbc 0,#67a8ce 100%) !important;background:-o-linear-gradient(#67a8ce,#3c8dbc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#67a8ce',endColorstr='#3c8dbc',GradientType=0) !important;color:#fff}.bg-blue-gradient{background:#0073b7 !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#0073b7),color-stop(1,#0089db)) !important;background:-ms-linear-gradient(bottom,#0073b7,#0089db) !important;background:-moz-linear-gradient(center bottom,#0073b7 0,#0089db 100%) !important;background:-o-linear-gradient(#0089db,#0073b7) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0089db',endColorstr='#0073b7',GradientType=0) !important;color:#fff}.bg-aqua-gradient{background:#00c0ef !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#00c0ef),color-stop(1,#14d1ff)) !important;background:-ms-linear-gradient(bottom,#00c0ef,#14d1ff) !important;background:-moz-linear-gradient(center bottom,#00c0ef 0,#14d1ff 100%) !important;background:-o-linear-gradient(#14d1ff,#00c0ef) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#14d1ff',endColorstr='#00c0ef',GradientType=0) !important;color:#fff}.bg-yellow-gradient{background:#f39c12 !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#f39c12),color-stop(1,#f7bc60)) !important;background:-ms-linear-gradient(bottom,#f39c12,#f7bc60) !important;background:-moz-linear-gradient(center bottom,#f39c12 0,#f7bc60 100%) !important;background:-o-linear-gradient(#f7bc60,#f39c12) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f7bc60',endColorstr='#f39c12',GradientType=0) !important;color:#fff}.bg-purple-gradient{background:#605ca8 !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#605ca8),color-stop(1,#9491c4)) !important;background:-ms-linear-gradient(bottom,#605ca8,#9491c4) !important;background:-moz-linear-gradient(center bottom,#605ca8 0,#9491c4 100%) !important;background:-o-linear-gradient(#9491c4,#605ca8) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#9491c4',endColorstr='#605ca8',GradientType=0) !important;color:#fff}.bg-green-gradient{background:#00a65a !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#00a65a),color-stop(1,#00ca6d)) !important;background:-ms-linear-gradient(bottom,#00a65a,#00ca6d) !important;background:-moz-linear-gradient(center bottom,#00a65a 0,#00ca6d 100%) !important;background:-o-linear-gradient(#00ca6d,#00a65a) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ca6d',endColorstr='#00a65a',GradientType=0) !important;color:#fff}.bg-red-gradient{background:#dd4b39 !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#dd4b39),color-stop(1,#e47365)) !important;background:-ms-linear-gradient(bottom,#dd4b39,#e47365) !important;background:-moz-linear-gradient(center bottom,#dd4b39 0,#e47365 100%) !important;background:-o-linear-gradient(#e47365,#dd4b39) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e47365',endColorstr='#dd4b39',GradientType=0) !important;color:#fff}.bg-black-gradient{background:#111 !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#111),color-stop(1,#2b2b2b)) !important;background:-ms-linear-gradient(bottom,#111,#2b2b2b) !important;background:-moz-linear-gradient(center bottom,#111 0,#2b2b2b 100%) !important;background:-o-linear-gradient(#2b2b2b,#111) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2b2b2b',endColorstr='#111111',GradientType=0) !important;color:#fff}.bg-maroon-gradient{background:#d81b60 !important;background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#d81b60),color-stop(1,#e73f7c)) !important;background:-ms-linear-gradient(bottom,#d81b60,#e73f7c) !important;background:-moz-linear-gradient(center bottom,#d81b60 0,#e73f7c 100%) !important;background:-o-linear-gradient(#e73f7c,#d81b60) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e73f7c',endColorstr='#d81b60',GradientType=0) !important;color:#fff}.description-block .description-icon{font-size:16px}.no-pad-top{padding-top:0}.position-static{position:static !important}.list-header{font-size:15px;padding:10px 4px;font-weight:bold;color:#666}.list-seperator{height:1px;background:#f4f4f4;margin:15px 0 9px 0}.list-link>a{padding:4px;color:#777}.list-link>a:hover{color:#222}.font-light{font-weight:300}.user-block:before,.user-block:after{content:" ";display:table}.user-block:after{clear:both}.user-block img{width:40px;height:40px;float:left}.user-block .username,.user-block .description,.user-block .comment{display:block;margin-left:50px}.user-block .username{font-size:16px;font-weight:600}.user-block .description{color:#999;font-size:13px}.user-block.user-block-sm .username,.user-block.user-block-sm .description,.user-block.user-block-sm .comment{margin-left:40px}.user-block.user-block-sm .username{font-size:14px}.img-sm,.img-md,.img-lg,.box-comments .box-comment img,.user-block.user-block-sm img{float:left}.img-sm,.box-comments .box-comment img,.user-block.user-block-sm img{width:30px !important;height:30px !important}.img-sm+.img-push{margin-left:40px}.img-md{width:60px;height:60px}.img-md+.img-push{margin-left:70px}.img-lg{width:100px;height:100px}.img-lg+.img-push{margin-left:110px}.img-bordered{border:3px solid #d2d6de;padding:3px}.img-bordered-sm{border:2px solid #d2d6de;padding:2px}.attachment-block{border:1px solid #f4f4f4;padding:5px;margin-bottom:10px;background:#f7f7f7}.attachment-block .attachment-img{max-width:100px;max-height:100px;height:auto;float:left}.attachment-block .attachment-pushed{margin-left:110px}.attachment-block .attachment-heading{margin:0}.attachment-block .attachment-text{color:#555}.connectedSortable{min-height:100px}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sort-highlight{background:#f4f4f4;border:1px dashed #ddd;margin-bottom:10px}.full-opacity-hover{opacity:.65;filter:alpha(opacity=65)}.full-opacity-hover:hover{opacity:1;filter:alpha(opacity=100)}.chart{position:relative;overflow:hidden;width:100%}.chart svg,.chart canvas{width:100% !important}@media print{.no-print,.main-sidebar,.left-side,.main-header,.content-header{display:none !important}.content-wrapper,.right-side,.main-footer{margin-left:0 !important;min-height:0 !important;-webkit-transform:translate(0,0) !important;-ms-transform:translate(0,0) !important;-o-transform:translate(0,0) !important;transform:translate(0,0) !important}.fixed .content-wrapper,.fixed .right-side{padding-top:0 !important}.invoice{width:100%;border:0;margin:0;padding:0}.invoice-col{float:left;width:33.3333333%}.table-responsive{overflow:auto}.table-responsive>.table tr th,.table-responsive>.table tr td{white-space:normal !important}} \ No newline at end of file +!*/html,body{min-height:100%}.layout-boxed html,.layout-boxed body{height:100%}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:"Source Sans Pro","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;overflow-x:hidden;overflow-y:auto}.wrapper{min-height:100%;position:relative;overflow:hidden}.wrapper:before,.wrapper:after{content:" ";display:table}.wrapper:after{clear:both}.layout-boxed .wrapper{max-width:1250px;margin:0 auto;min-height:100%;box-shadow:0 0 8px rgba(0, 0, 0, 0.5);position:relative}.layout-boxed{background:url("../img/boxed-bg.jpg") repeat fixed}.content-wrapper,.right-side,.main-footer{-webkit-transition:-webkit-transform .3s ease-in-out,margin .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,margin .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,margin .3s ease-in-out;transition:transform .3s ease-in-out,margin .3s ease-in-out;margin-left:230px;z-index:820}.layout-top-nav .content-wrapper,.layout-top-nav .right-side,.layout-top-nav .main-footer{margin-left:0}@media(max-width: 767px){.content-wrapper,.right-side,.main-footer{margin-left:0}}@media(min-width: 768px){.sidebar-collapse .content-wrapper,.sidebar-collapse .right-side,.sidebar-collapse .main-footer{margin-left:0}}@media(max-width: 767px){.sidebar-open .content-wrapper,.sidebar-open .right-side,.sidebar-open .main-footer{-webkit-transform:translate(230px, 0);-ms-transform:translate(230px, 0);-o-transform:translate(230px, 0);transform:translate(230px, 0)}}.content-wrapper,.right-side{min-height:100%;background-color:#ecf0f5;z-index:800}.main-footer{background:#fff;padding:15px;color:#444;border-top:1px solid #d2d6de}.fixed .main-header,.fixed .main-sidebar,.fixed .left-side{position:fixed}.fixed .main-header{top:0;right:0;left:0}.fixed .content-wrapper,.fixed .right-side{padding-top:50px}@media(max-width: 767px){.fixed .content-wrapper,.fixed .right-side{padding-top:100px}}.fixed.layout-boxed .wrapper{max-width:100%}body.hold-transition .content-wrapper,body.hold-transition .right-side,body.hold-transition .main-footer,body.hold-transition .main-sidebar,body.hold-transition .left-side,body.hold-transition .main-header .navbar,body.hold-transition .main-header .logo{-webkit-transition:none;-o-transition:none;transition:none}.content{min-height:250px;padding:15px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Source Sans Pro",sans-serif}a{color:#3c8dbc}a:hover,a:active,a:focus{outline:none;text-decoration:none;color:#72afd2}.page-header{margin:10px 0 20px 0;font-size:22px}.page-header > small{color:#666;display:block;margin-top:5px}.main-header{position:relative;max-height:100px;z-index:1030}.main-header .navbar{-webkit-transition:margin-left .3s ease-in-out;-o-transition:margin-left .3s ease-in-out;transition:margin-left .3s ease-in-out;margin-bottom:0;margin-left:230px;border:none;min-height:50px;border-radius:0}.layout-top-nav .main-header .navbar{margin-left:0}.main-header #navbar-search-input.form-control{background:rgba(255, 255, 255, 0.2);border-color:transparent}.main-header #navbar-search-input.form-control:focus,.main-header #navbar-search-input.form-control:active{border-color:rgba(0, 0, 0, 0.1);background:rgba(255, 255, 255, 0.9)}.main-header #navbar-search-input.form-control::-moz-placeholder{color:#ccc;opacity:1}.main-header #navbar-search-input.form-control:-ms-input-placeholder{color:#ccc}.main-header #navbar-search-input.form-control::-webkit-input-placeholder{color:#ccc}.main-header .navbar-custom-menu,.main-header .navbar-right{float:right}@media(max-width: 991px){.main-header .navbar-custom-menu a,.main-header .navbar-right a{color:inherit;background:transparent}}@media(max-width: 767px){.main-header .navbar-right{float:none}.navbar-collapse .main-header .navbar-right{margin:7.5px -15px}.main-header .navbar-right > li{color:inherit;border:0}}.main-header .sidebar-toggle{float:left;background-color:transparent;background-image:none;padding:15px 15px;font-family:fontAwesome}.main-header .sidebar-toggle:before{content:""}.main-header .sidebar-toggle:hover{color:#fff}.main-header .sidebar-toggle:focus,.main-header .sidebar-toggle:active{background:transparent}.main-header .sidebar-toggle .icon-bar{display:none}.main-header .no_worker_warning{float:left;color:white;font-weight:600;letter-spacing:.25px;border-bottom:#dd4b39 solid 2px;margin-top:12px;padding:3px 3px 3px 5px;transition:1s}.main-header .no_worker_warning:hover{color:red;background-color:black;opacity:1;border-bottom:black none 2px;border-radius:5px;transition:1s}.main-header .no_worker_warning > i.fa{padding:2px 5px 2px 2px;color:#dd4b39;text-shadow:0 0 1px #000}.main-header .navbar .nav > li.user > a > .fa,.main-header .navbar .nav > li.user > a > .glyphicon,.main-header .navbar .nav > li.user > a > .ion{margin-right:5px}.main-header .navbar .nav > li > a > .label{position:absolute;top:9px;right:7px;text-align:center;font-size:9px;padding:2px 3px;line-height:.9}.main-header .logo{-webkit-transition:width .3s ease-in-out;-o-transition:width .3s ease-in-out;transition:width .3s ease-in-out;display:block;float:left;height:50px;font-size:20px;line-height:50px;text-align:center;width:230px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;padding:0 15px;font-weight:300;overflow:hidden}.main-header .logo .logo-lg{display:block}.main-header .logo .logo-mini{display:none}.main-header .navbar-brand{color:#fff}.content-header{position:relative;padding:15px 15px 0 15px}.content-header > h1{margin:0;font-size:24px}.content-header > h1 > small{font-size:15px;display:inline-block;padding-left:4px;font-weight:300}.content-header > .breadcrumb{float:right;background:transparent;margin-top:0;margin-bottom:0;font-size:12px;padding:7px 5px;position:absolute;top:15px;right:10px;border-radius:2px}.content-header > .breadcrumb > li > a{color:#444;text-decoration:none;display:inline-block}.content-header > .breadcrumb > li > a > .fa,.content-header > .breadcrumb > li > a > .glyphicon,.content-header > .breadcrumb > li > a > .ion{margin-right:5px}.content-header > .breadcrumb > li + li:before{content:"> "}@media(max-width: 991px){.content-header > .breadcrumb{position:relative;margin-top:5px;top:0;right:0;float:none;background:#d2d6de;padding-left:10px}.content-header > .breadcrumb li:before{color:#97a0b3}}.navbar-toggle{color:#fff;border:0;margin:0;padding:15px 15px}@media(max-width: 991px){.navbar-custom-menu .navbar-nav > li{float:left}.navbar-custom-menu .navbar-nav{margin:0;float:left}.navbar-custom-menu .navbar-nav > li > a{padding-top:15px;padding-bottom:15px;line-height:20px}}@media(max-width: 767px){.main-header{position:relative}.main-header .logo,.main-header .navbar{width:100%;float:none}.main-header .navbar{margin:0}.main-header .navbar-custom-menu{float:right}}@media(max-width: 991px){.navbar-collapse.pull-left{float:none !important}.navbar-collapse.pull-left + .navbar-custom-menu{display:block;position:absolute;top:0;right:40px}}.main-sidebar,.left-side{position:absolute;top:0;left:0;padding-top:50px;min-height:100%;width:230px;z-index:810;-webkit-transition:-webkit-transform .3s ease-in-out,width .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,width .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,width .3s ease-in-out;transition:transform .3s ease-in-out,width .3s ease-in-out}@media(max-width: 767px){.main-sidebar,.left-side{padding-top:100px}}@media(max-width: 767px){.main-sidebar,.left-side{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media(min-width: 768px){.sidebar-collapse .main-sidebar,.sidebar-collapse .left-side{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media(max-width: 767px){.sidebar-open .main-sidebar,.sidebar-open .left-side{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}}.sidebar{padding-bottom:10px}.sidebar-form input:focus{border-color:transparent}.user-panel{position:relative;width:100%;padding:10px;overflow:hidden}.user-panel:before,.user-panel:after{content:" ";display:table}.user-panel:after{clear:both}.user-panel > .image > img{width:100%;max-width:45px;height:auto}.user-panel > .info{padding:5px 5px 5px 15px;line-height:1;position:absolute;left:55px}.user-panel > .info > p{font-weight:600;margin-bottom:9px}.user-panel > .info > a{text-decoration:none;padding-right:5px;margin-top:3px;font-size:11px}.user-panel > .info > a > .fa,.user-panel > .info > a > .ion,.user-panel > .info > a > .glyphicon{margin-right:3px}.sidebar-menu{list-style:none;margin:0;padding:0}.sidebar-menu > li{position:relative;margin:0;padding:0}.sidebar-menu > li > a{padding:12px 5px 12px 15px;display:block}.sidebar-menu > li > a > .fa,.sidebar-menu > li > a > .glyphicon,.sidebar-menu > li > a > .ion{width:20px}.sidebar-menu > li .label,.sidebar-menu > li .badge{margin-right:5px}.sidebar-menu > li .badge{margin-top:3px}.sidebar-menu li.header{padding:10px 25px 10px 15px;font-size:12px}.sidebar-menu li > a > .fa-angle-left,.sidebar-menu li > a > .pull-right-container > .fa-angle-left{width:auto;height:auto;padding:0;margin-right:10px}.sidebar-menu li.active > a > .fa-angle-left,.sidebar-menu li.active > a > .pull-right-container > .fa-angle-left{-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.sidebar-menu li.active > .treeview-menu{display:block}.sidebar-menu .treeview-menu{display:none;list-style:none;padding:0;margin:0;padding-left:5px}.sidebar-menu .treeview-menu .treeview-menu{padding-left:20px}.sidebar-menu .treeview-menu > li{margin:0}.sidebar-menu .treeview-menu > li > a{padding:5px 5px 5px 15px;display:block;font-size:14px}.sidebar-menu .treeview-menu > li > a > .fa,.sidebar-menu .treeview-menu > li > a > .glyphicon,.sidebar-menu .treeview-menu > li > a > .ion{width:20px}.sidebar-menu .treeview-menu > li > a > .pull-right-container > .fa-angle-left,.sidebar-menu .treeview-menu > li > a > .pull-right-container > .fa-angle-down,.sidebar-menu .treeview-menu > li > a > .fa-angle-left,.sidebar-menu .treeview-menu > li > a > .fa-angle-down{width:auto}@media(min-width: 768px){.sidebar-mini.sidebar-collapse .content-wrapper,.sidebar-mini.sidebar-collapse .right-side,.sidebar-mini.sidebar-collapse .main-footer{margin-left:50px !important;z-index:840}.sidebar-mini.sidebar-collapse .main-sidebar{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);width:50px !important;z-index:850}.sidebar-mini.sidebar-collapse .sidebar-menu > li{position:relative}.sidebar-mini.sidebar-collapse .sidebar-menu > li > a{margin-right:0}.sidebar-mini.sidebar-collapse .sidebar-menu > li > a > span{border-top-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu > li:not(.treeview) > a > span{border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu{padding-top:5px;padding-bottom:5px;border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right),.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > .treeview-menu{display:block !important;position:absolute;width:180px;left:50px}.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span{top:0;margin-left:-3px;padding:12px 5px 12px 20px;background-color:inherit}.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > .pull-right-container{float:right;width:auto !important;left:200px !important;top:10px !important}.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > .pull-right-container > .label:not(:first-of-type){display:none}.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > .treeview-menu{top:44px;margin-left:0}.sidebar-mini.sidebar-collapse .main-sidebar .user-panel > .info,.sidebar-mini.sidebar-collapse .sidebar-form,.sidebar-mini.sidebar-collapse .sidebar-menu > li > a > span,.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu,.sidebar-mini.sidebar-collapse .sidebar-menu > li > a > .pull-right,.sidebar-mini.sidebar-collapse .sidebar-menu li.header{display:none !important;-webkit-transform:translateZ(0)}.sidebar-mini.sidebar-collapse .main-header .logo{width:50px}.sidebar-mini.sidebar-collapse .main-header .logo > .logo-mini{display:block;margin-left:-15px;margin-right:-15px;font-size:18px}.sidebar-mini.sidebar-collapse .main-header .logo > .logo-lg{display:none}.sidebar-mini.sidebar-collapse .main-header .navbar{margin-left:50px}}.sidebar-menu,.main-sidebar .user-panel,.sidebar-menu > li.header{white-space:nowrap;overflow:hidden}.sidebar-menu:hover{overflow:visible}.sidebar-form,.sidebar-menu > li.header{overflow:hidden;text-overflow:clip}.sidebar-menu li > a{position:relative}.sidebar-menu li > a > .pull-right-container{position:absolute;right:10px;top:50%;margin-top:-7px}.control-sidebar-bg{position:fixed;z-index:1000;bottom:0}.control-sidebar-bg,.control-sidebar{top:0;right:-230px;width:230px;-webkit-transition:right .3s ease-in-out;-o-transition:right .3s ease-in-out;transition:right .3s ease-in-out}.control-sidebar{position:absolute;padding-top:50px;z-index:1010}@media(max-width: 768px){.control-sidebar{padding-top:100px}}.control-sidebar > .tab-content{padding:10px 15px}.control-sidebar.control-sidebar-open,.control-sidebar.control-sidebar-open + .control-sidebar-bg{right:0}.control-sidebar-open .control-sidebar-bg,.control-sidebar-open .control-sidebar{right:0}@media(min-width: 768px){.control-sidebar-open .content-wrapper,.control-sidebar-open .right-side,.control-sidebar-open .main-footer{margin-right:230px}}.nav-tabs.control-sidebar-tabs > li:first-of-type > a,.nav-tabs.control-sidebar-tabs > li:first-of-type > a:hover,.nav-tabs.control-sidebar-tabs > li:first-of-type > a:focus{border-left-width:0}.nav-tabs.control-sidebar-tabs > li > a{border-radius:0}.nav-tabs.control-sidebar-tabs > li > a,.nav-tabs.control-sidebar-tabs > li > a:hover{border-top:none;border-right:none;border-left:1px solid transparent;border-bottom:1px solid transparent}.nav-tabs.control-sidebar-tabs > li > a .icon{font-size:16px}.nav-tabs.control-sidebar-tabs > li.active > a,.nav-tabs.control-sidebar-tabs > li.active > a:hover,.nav-tabs.control-sidebar-tabs > li.active > a:focus,.nav-tabs.control-sidebar-tabs > li.active > a:active{border-top:none;border-right:none;border-bottom:none}@media(max-width: 768px){.nav-tabs.control-sidebar-tabs{display:table}.nav-tabs.control-sidebar-tabs > li{display:table-cell}}.control-sidebar-heading{font-weight:400;font-size:16px;padding:10px 0;margin-bottom:10px}.control-sidebar-subheading{display:block;font-weight:400;font-size:14px}.control-sidebar-menu{list-style:none;padding:0;margin:0 -15px}.control-sidebar-menu > li > a{display:block;padding:10px 15px}.control-sidebar-menu > li > a:before,.control-sidebar-menu > li > a:after{content:" ";display:table}.control-sidebar-menu > li > a:after{clear:both}.control-sidebar-menu > li > a > .control-sidebar-subheading{margin-top:0}.control-sidebar-menu .menu-icon{float:left;width:35px;height:35px;border-radius:50%;text-align:center;line-height:35px}.control-sidebar-menu .menu-info{margin-left:45px;margin-top:3px}.control-sidebar-menu .menu-info > .control-sidebar-subheading{margin:0}.control-sidebar-menu .menu-info > p{margin:0;font-size:11px}.control-sidebar-menu .progress{margin:0}.control-sidebar-dark{color:#b8c7ce}.control-sidebar-dark,.control-sidebar-dark + .control-sidebar-bg{background:#222d32}.control-sidebar-dark .nav-tabs.control-sidebar-tabs{border-bottom:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a{background:#181f23;color:#b8c7ce}.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:focus{border-left-color:#141a1d;border-bottom-color:#141a1d}.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:active{background:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:hover{color:#fff}.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a:active{background:#222d32;color:#fff}.control-sidebar-dark .control-sidebar-heading,.control-sidebar-dark .control-sidebar-subheading{color:#fff}.control-sidebar-dark .control-sidebar-menu > li > a:hover{background:#1e282c}.control-sidebar-dark .control-sidebar-menu > li > a .menu-info > p{color:#b8c7ce}.control-sidebar-light{color:#5e5e5e}.control-sidebar-light,.control-sidebar-light + .control-sidebar-bg{background:#f9fafc;border-left:1px solid #d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs{border-bottom:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a{background:#e8ecf4;color:#444}.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:focus{border-left-color:#d2d6de;border-bottom-color:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:active{background:#eff1f7}.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a:active{background:#f9fafc;color:#111}.control-sidebar-light .control-sidebar-heading,.control-sidebar-light .control-sidebar-subheading{color:#111}.control-sidebar-light .control-sidebar-menu{margin-left:-14px}.control-sidebar-light .control-sidebar-menu > li > a:hover{background:#f4f4f5}.control-sidebar-light .control-sidebar-menu > li > a .menu-info > p{color:#5e5e5e}.dropdown-menu{box-shadow:none;border-color:#eee}.dropdown-menu > li > a{color:#777}.dropdown-menu > li > a > .glyphicon,.dropdown-menu > li > a > .fa,.dropdown-menu > li > a > .ion{margin-right:10px}.dropdown-menu > li > a:hover{background-color:#e1e3e9;color:#333}.dropdown-menu > .divider{background-color:#eee}.navbar-nav > .notifications-menu > .dropdown-menu,.navbar-nav > .messages-menu > .dropdown-menu,.navbar-nav > .tasks-menu > .dropdown-menu{width:280px;padding:0 0 0 0;margin:0;top:100%}.navbar-nav > .notifications-menu > .dropdown-menu > li,.navbar-nav > .messages-menu > .dropdown-menu > li,.navbar-nav > .tasks-menu > .dropdown-menu > li{position:relative}.navbar-nav > .notifications-menu > .dropdown-menu > li.header,.navbar-nav > .messages-menu > .dropdown-menu > li.header,.navbar-nav > .tasks-menu > .dropdown-menu > li.header{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#fff;padding:7px 10px;border-bottom:1px solid #f4f4f4;color:#444;font-size:14px}.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a,.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a,.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;font-size:12px;background-color:#fff;padding:7px 10px;border-bottom:1px solid #eee;color:#444 !important;text-align:center}@media(max-width: 991px){.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a,.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a,.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a{background:#fff !important;color:#444 !important}}.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a:hover,.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a:hover,.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a:hover{text-decoration:none;font-weight:normal}.navbar-nav > .notifications-menu > .dropdown-menu > li .menu,.navbar-nav > .messages-menu > .dropdown-menu > li .menu,.navbar-nav > .tasks-menu > .dropdown-menu > li .menu{max-height:200px;margin:0;padding:0;list-style:none;overflow-x:hidden}.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a,.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a,.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a{display:block;white-space:nowrap;border-bottom:1px solid #f4f4f4}.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a:hover,.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:hover,.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a:hover{background:#f4f4f4;text-decoration:none}.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a{color:#444;overflow:hidden;text-overflow:ellipsis;padding:10px}.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon,.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa,.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion{width:20px}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a{margin:0;padding:10px 10px}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > div > img{margin:auto 10px auto auto;width:40px;height:40px}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > h4{padding:0;margin:0 0 0 45px;color:#444;font-size:15px;position:relative}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > h4 > small{color:#999;font-size:10px;position:absolute;top:0;right:0}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > p{margin:0 0 0 45px;font-size:12px;color:#888}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:before,.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:after{content:" ";display:table}.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:after{clear:both}.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a{padding:10px}.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a > h3{font-size:14px;padding:0;margin:0 0 10px 0;color:#666}.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a > .progress{padding:0;margin:0}.navbar-nav > .user-menu > .dropdown-menu{border-top-right-radius:0;border-top-left-radius:0;padding:1px 0 0 0;border-top-width:0;width:380px}.navbar-nav > .user-menu > .dropdown-menu,.navbar-nav > .user-menu > .dropdown-menu > .user-body{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.navbar-nav > .user-menu > .dropdown-menu > li.user-header{height:175px;padding:10px;text-align:center}.navbar-nav > .user-menu > .dropdown-menu > li.user-header > img{z-index:5;height:90px;width:90px;border:3px solid;border-color:transparent;border-color:rgba(255, 255, 255, 0.2)}.navbar-nav > .user-menu > .dropdown-menu > li.user-header > p{z-index:5;color:#fff;color:rgba(255, 255, 255, 0.8);font-size:17px;margin-top:10px}.navbar-nav > .user-menu > .dropdown-menu > li.user-header > p > small{display:block;font-size:12px}.navbar-nav > .user-menu > .dropdown-menu > .user-body{padding:15px;border-bottom:1px solid #f4f4f4;border-top:1px solid #ddd}.navbar-nav > .user-menu > .dropdown-menu > .user-body:before,.navbar-nav > .user-menu > .dropdown-menu > .user-body:after{content:" ";display:table}.navbar-nav > .user-menu > .dropdown-menu > .user-body:after{clear:both}.navbar-nav > .user-menu > .dropdown-menu > .user-body a{color:#444 !important}@media(max-width: 991px){.navbar-nav > .user-menu > .dropdown-menu > .user-body a{background:#fff !important;color:#444 !important}}.navbar-nav > .user-menu > .dropdown-menu > .user-footer{background-color:#f9f9f9;padding:10px;text-align:center}.navbar-nav > .user-menu > .dropdown-menu > .user-footer:before,.navbar-nav > .user-menu > .dropdown-menu > .user-footer:after{content:" ";display:table}.navbar-nav > .user-menu > .dropdown-menu > .user-footer:after{clear:both}.navbar-nav > .user-menu > .dropdown-menu > .user-footer .btn-default{color:#666}@media(max-width: 991px){.navbar-nav > .user-menu > .dropdown-menu > .user-footer .btn-default:hover{background-color:#f9f9f9}}.navbar-nav > .user-menu .user-image{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px;margin-top:-2px}@media(max-width: 767px){.navbar-nav > .user-menu .user-image{float:none;margin-right:0;margin-top:-8px;line-height:10px}}.open:not(.dropup) > .animated-dropdown-menu{backface-visibility:visible !important;-webkit-animation:flipInX .7s both;-o-animation:flipInX .7s both;animation:flipInX .7s both}@keyframes flipInX{0%{transform:perspective(400px) rotate3d(1, 0, 0, 90deg);transition-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1, 0, 0, -20deg);transition-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{transform:perspective(400px)}}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 90deg);-webkit-transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -20deg);-webkit-transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{-webkit-transform:perspective(400px)}}.navbar-custom-menu > .navbar-nav > li{position:relative}.navbar-custom-menu > .navbar-nav > li > .dropdown-menu{position:absolute;right:0;left:auto}@media(max-width: 991px){.navbar-custom-menu > .navbar-nav{float:right}.navbar-custom-menu > .navbar-nav > li{position:static}.navbar-custom-menu > .navbar-nav > li > .dropdown-menu{position:absolute;right:5%;left:auto;border:1px solid #ddd;background:#fff}}.form-control{border-radius:0;box-shadow:none;border-color:#d2d6de}.form-control:focus{border-color:#3c8dbc;box-shadow:none}.form-control::-moz-placeholder,.form-control:-ms-input-placeholder,.form-control::-webkit-input-placeholder{color:#bbb;opacity:1}.form-control:not(select){-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-group.has-success label{color:#00a65a}.form-group.has-success .form-control,.form-group.has-success .input-group-addon{border-color:#00a65a;box-shadow:none}.form-group.has-success .help-block{color:#00a65a}.form-group.has-warning label{color:#f39c12}.form-group.has-warning .form-control,.form-group.has-warning .input-group-addon{border-color:#f39c12;box-shadow:none}.form-group.has-warning .help-block{color:#f39c12}.form-group.has-error label{color:#dd4b39}.form-group.has-error .form-control,.form-group.has-error .input-group-addon{border-color:#dd4b39;box-shadow:none}.form-group.has-error .help-block{color:#dd4b39}.input-group .input-group-addon{border-radius:0;border-color:#d2d6de;background-color:#fff}.btn-group-vertical .btn.btn-flat:first-of-type,.btn-group-vertical .btn.btn-flat:last-of-type{border-radius:0}.icheck > label{padding-left:0}.form-control-feedback.fa{line-height:34px}.input-lg + .form-control-feedback.fa,.input-group-lg + .form-control-feedback.fa,.form-group-lg .form-control + .form-control-feedback.fa{line-height:46px}.input-sm + .form-control-feedback.fa,.input-group-sm + .form-control-feedback.fa,.form-group-sm .form-control + .form-control-feedback.fa{line-height:30px}.progress,.progress > .progress-bar{-webkit-box-shadow:none;box-shadow:none}.progress,.progress > .progress-bar,.progress .progress-bar,.progress > .progress-bar .progress-bar{border-radius:1px}.progress.sm,.progress-sm{height:10px}.progress.sm,.progress-sm,.progress.sm .progress-bar,.progress-sm .progress-bar{border-radius:1px}.progress.xs,.progress-xs{height:7px}.progress.xs,.progress-xs,.progress.xs .progress-bar,.progress-xs .progress-bar{border-radius:1px}.progress.xxs,.progress-xxs{height:3px}.progress.xxs,.progress-xxs,.progress.xxs .progress-bar,.progress-xxs .progress-bar{border-radius:1px}.progress.vertical{position:relative;width:30px;height:200px;display:inline-block;margin-right:10px}.progress.vertical > .progress-bar{width:100%;position:absolute;bottom:0}.progress.vertical.sm,.progress.vertical.progress-sm{width:20px}.progress.vertical.xs,.progress.vertical.progress-xs{width:10px}.progress.vertical.xxs,.progress.vertical.progress-xxs{width:3px}.progress-group .progress-text{font-weight:600}.progress-group .progress-number{float:right}.table tr > td .progress{margin:0}.progress-bar-light-blue,.progress-bar-primary{background-color:#3c8dbc}.progress-striped .progress-bar-light-blue,.progress-striped .progress-bar-primary{background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)}.progress-bar-green,.progress-bar-success{background-color:#00a65a}.progress-striped .progress-bar-green,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)}.progress-bar-aqua,.progress-bar-info{background-color:#00c0ef}.progress-striped .progress-bar-aqua,.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)}.progress-bar-yellow,.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-yellow,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)}.progress-bar-red,.progress-bar-danger{background-color:#dd4b39}.progress-striped .progress-bar-red,.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)}.small-box{border-radius:2px;position:relative;display:block;margin-bottom:20px;box-shadow:0 1px 1px rgba(0, 0, 0, 0.1)}.small-box > .inner{padding:10px}.small-box > .small-box-footer{position:relative;text-align:center;padding:3px 0;color:#fff;color:rgba(255, 255, 255, 0.8);display:block;z-index:10;background:rgba(0, 0, 0, 0.1);text-decoration:none}.small-box > .small-box-footer:hover{color:#fff;background:rgba(0, 0, 0, 0.15)}.small-box h3{font-size:38px;font-weight:bold;margin:0 0 10px 0;white-space:nowrap;padding:0}.small-box p{font-size:15px}.small-box p > small{display:block;color:#f9f9f9;font-size:13px;margin-top:5px}.small-box h3,.small-box p{z-index:5}.small-box .icon{-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;position:absolute;top:-10px;right:10px;z-index:0;font-size:90px;color:rgba(0, 0, 0, 0.15)}.small-box:hover{text-decoration:none;color:#f9f9f9}.small-box:hover .icon{font-size:95px}@media(max-width: 767px){.small-box{text-align:center}.small-box .icon{display:none}.small-box p{font-size:12px}}.box{position:relative;border-radius:3px;background:#fff;border-top:3px solid #d2d6de;margin-bottom:20px;width:100%;box-shadow:0 1px 1px rgba(0, 0, 0, 0.1)}.box.box-primary{border-top-color:#3c8dbc}.box.box-info{border-top-color:#00c0ef}.box.box-danger{border-top-color:#dd4b39}.box.box-warning{border-top-color:#f39c12}.box.box-success{border-top-color:#00a65a}.box.box-default{border-top-color:#d2d6de}.box.collapsed-box .box-body,.box.collapsed-box .box-footer{display:none}.box .nav-stacked > li{border-bottom:1px solid #f4f4f4;margin:0}.box .nav-stacked > li:last-of-type{border-bottom:none}.box.height-control .box-body{max-height:300px;overflow:auto}.box .border-right{border-right:1px solid #f4f4f4}.box .border-left{border-left:1px solid #f4f4f4}.box.box-solid{border-top:0}.box.box-solid > .box-header .btn.btn-default{background:transparent}.box.box-solid > .box-header .btn:hover,.box.box-solid > .box-header a:hover{background:rgba(0, 0, 0, 0.1)}.box.box-solid.box-default{border:1px solid #d2d6de}.box.box-solid.box-default > .box-header{color:#444;background:#d2d6de;background-color:#d2d6de}.box.box-solid.box-default > .box-header a,.box.box-solid.box-default > .box-header .btn{color:#444}.box.box-solid.box-primary{border:1px solid #3c8dbc}.box.box-solid.box-primary > .box-header{color:#fff;background:#3c8dbc;background-color:#3c8dbc}.box.box-solid.box-primary > .box-header a,.box.box-solid.box-primary > .box-header .btn{color:#fff}.box.box-solid.box-info{border:1px solid #00c0ef}.box.box-solid.box-info > .box-header{color:#fff;background:#00c0ef;background-color:#00c0ef}.box.box-solid.box-info > .box-header a,.box.box-solid.box-info > .box-header .btn{color:#fff}.box.box-solid.box-danger{border:1px solid #dd4b39}.box.box-solid.box-danger > .box-header{color:#fff;background:#dd4b39;background-color:#dd4b39}.box.box-solid.box-danger > .box-header a,.box.box-solid.box-danger > .box-header .btn{color:#fff}.box.box-solid.box-warning{border:1px solid #f39c12}.box.box-solid.box-warning > .box-header{color:#fff;background:#f39c12;background-color:#f39c12}.box.box-solid.box-warning > .box-header a,.box.box-solid.box-warning > .box-header .btn{color:#fff}.box.box-solid.box-success{border:1px solid #00a65a}.box.box-solid.box-success > .box-header{color:#fff;background:#00a65a;background-color:#00a65a}.box.box-solid.box-success > .box-header a,.box.box-solid.box-success > .box-header .btn{color:#fff}.box.box-solid > .box-header > .box-tools .btn{border:0;box-shadow:none}.box.box-solid[class*=bg] > .box-header{color:#fff}.box .box-group > .box{margin-bottom:5px}.box .knob-label{text-align:center;color:#333;font-weight:100;font-size:12px;margin-bottom:.3em}.box > .overlay,.overlay-wrapper > .overlay,.box > .loading-img,.overlay-wrapper > .loading-img{position:absolute;top:0;left:0;width:100%;height:100%}.box .overlay,.overlay-wrapper .overlay{z-index:50;background:rgba(255, 255, 255, 0.7);border-radius:3px}.box .overlay > .fa,.overlay-wrapper .overlay > .fa{position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-15px;color:#000;font-size:30px}.box .overlay.dark,.overlay-wrapper .overlay.dark{background:rgba(0, 0, 0, 0.5)}.box-header:before,.box-body:before,.box-footer:before,.box-header:after,.box-body:after,.box-footer:after{content:" ";display:table}.box-header:after,.box-body:after,.box-footer:after{clear:both}.box-header{color:#444;display:block;padding:10px;position:relative}.box-header.with-border{border-bottom:1px solid #f4f4f4}.collapsed-box .box-header.with-border{border-bottom:none}.box-header > .fa,.box-header > .glyphicon,.box-header > .ion,.box-header .box-title{display:inline-block;font-size:18px;margin:0;line-height:1}.box-header > .fa,.box-header > .glyphicon,.box-header > .ion{margin-right:5px}.box-header > .box-tools{position:absolute;right:10px;top:5px}.box-header > .box-tools [data-toggle=tooltip]{position:relative}.box-header > .box-tools.pull-right .dropdown-menu{right:0;left:auto}.btn-box-tool{padding:5px;font-size:12px;background:transparent;color:#97a0b3}.open .btn-box-tool,.btn-box-tool:hover{color:#606c84}.btn-box-tool.btn:active{box-shadow:none}.box-body{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;padding:10px}.no-header .box-body{border-top-right-radius:3px;border-top-left-radius:3px}.box-body > .table{margin-bottom:0}.box-body .fc{margin-top:5px}.box-body .full-width-chart{margin:-19px}.box-body.no-padding .full-width-chart{margin:-9px}.box-body .box-pane{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px}.box-body .box-pane-right{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:0}.box-footer{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border-top:1px solid #f4f4f4;padding:10px;background-color:#fff}.chart-legend{margin:10px 0}@media(max-width: 991px){.chart-legend > li{float:left;margin-right:10px}}.box-comments{background:#f7f7f7}.box-comments .box-comment{padding:8px 0;border-bottom:1px solid #eee}.box-comments .box-comment:before,.box-comments .box-comment:after{content:" ";display:table}.box-comments .box-comment:after{clear:both}.box-comments .box-comment:last-of-type{border-bottom:0}.box-comments .box-comment:first-of-type{padding-top:0}.box-comments .box-comment img{float:left}.box-comments .comment-text{margin-left:40px;color:#555}.box-comments .username{color:#444;display:block;font-weight:600}.box-comments .text-muted{font-weight:400;font-size:12px}.todo-list{margin:0;padding:0;list-style:none;overflow:auto}.todo-list > li{border-radius:2px;padding:10px;background:#f4f4f4;margin-bottom:2px;border-left:2px solid #e6e7e8;color:#444}.todo-list > li:last-of-type{margin-bottom:0}.todo-list > li > input[type=checkbox]{margin:0 10px 0 5px}.todo-list > li .text{display:inline-block;margin-left:5px;font-weight:600}.todo-list > li .label{margin-left:10px;font-size:9px}.todo-list > li .tools{display:none;float:right;color:#dd4b39}.todo-list > li .tools > .fa,.todo-list > li .tools > .glyphicon,.todo-list > li .tools > .ion{margin-right:5px;cursor:pointer}.todo-list > li:hover .tools{display:inline-block}.todo-list > li.done{color:#999}.todo-list > li.done .text{text-decoration:line-through;font-weight:500}.todo-list > li.done .label{background:#d2d6de !important}.todo-list .danger{border-left-color:#dd4b39}.todo-list .warning{border-left-color:#f39c12}.todo-list .info{border-left-color:#00c0ef}.todo-list .success{border-left-color:#00a65a}.todo-list .primary{border-left-color:#3c8dbc}.todo-list .handle{display:inline-block;cursor:move;margin:0 5px}.chat{padding:5px 20px 5px 10px}.chat .item{margin-bottom:10px}.chat .item:before,.chat .item:after{content:" ";display:table}.chat .item:after{clear:both}.chat .item > img{width:40px;height:40px;border:2px solid transparent;border-radius:50%}.chat .item > .online{border:2px solid #00a65a}.chat .item > .offline{border:2px solid #dd4b39}.chat .item > .message{margin-left:55px;margin-top:-40px}.chat .item > .message > .name{display:block;font-weight:600}.chat .item > .attachment{border-radius:3px;background:#f4f4f4;margin-left:65px;margin-right:15px;padding:10px}.chat .item > .attachment > h4{margin:0 0 5px 0;font-weight:600;font-size:14px}.chat .item > .attachment > p,.chat .item > .attachment > .filename{font-weight:600;font-size:13px;font-style:italic;margin:0}.chat .item > .attachment:before,.chat .item > .attachment:after{content:" ";display:table}.chat .item > .attachment:after{clear:both}.box-input{max-width:200px}.modal .panel-body{color:#444}.info-box{display:block;min-height:90px;background:#fff;width:100%;box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);border-radius:2px;margin-bottom:15px}.info-box small{font-size:14px}.info-box .progress{background:rgba(0, 0, 0, 0.2);margin:5px -10px 5px -10px;height:2px}.info-box .progress,.info-box .progress .progress-bar{border-radius:0}.info-box .progress .progress-bar{background:#fff}.info-box-icon{border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px;display:block;float:left;height:90px;width:90px;text-align:center;font-size:45px;line-height:90px;background:rgba(0, 0, 0, 0.2)}.info-box-icon > img{max-width:100%}.info-box-content{padding:5px 10px;margin-left:90px}.info-box-number{display:block;font-weight:bold;font-size:18px}.progress-description,.info-box-text{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.info-box-text{text-transform:uppercase}.info-box-more{display:block}.progress-description{margin:0}.timeline{position:relative;margin:0 0 30px 0;padding:0;list-style:none}.timeline:before{content:"";position:absolute;top:0;bottom:0;width:4px;background:#ddd;left:31px;margin:0;border-radius:2px}.timeline > li{position:relative;margin-right:10px;margin-bottom:15px}.timeline > li:before,.timeline > li:after{content:" ";display:table}.timeline > li:after{clear:both}.timeline > li > .timeline-item{-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);border-radius:3px;margin-top:0;background:#fff;color:#444;margin-left:60px;margin-right:15px;padding:0;position:relative}.timeline > li > .timeline-item > .time{color:#999;float:right;padding:10px;font-size:12px}.timeline > li > .timeline-item > .timeline-header{margin:0;color:#555;border-bottom:1px solid #f4f4f4;padding:10px;font-size:16px;line-height:1.1}.timeline > li > .timeline-item > .timeline-header > a{font-weight:600}.timeline > li > .timeline-item > .timeline-body,.timeline > li > .timeline-item > .timeline-footer{padding:10px}.timeline > li > .fa,.timeline > li > .glyphicon,.timeline > li > .ion{width:30px;height:30px;font-size:15px;line-height:30px;position:absolute;color:#666;background:#d2d6de;border-radius:50%;text-align:center;left:18px;top:0}.timeline > .time-label > span{font-weight:600;padding:5px;display:inline-block;background-color:#fff;border-radius:4px}.timeline-inverse > li > .timeline-item{background:#f0f0f0;border:1px solid #ddd;-webkit-box-shadow:none;box-shadow:none}.timeline-inverse > li > .timeline-item > .timeline-header{border-bottom-color:#ddd}.btn{border-radius:3px;-webkit-box-shadow:none;box-shadow:none;border:1px solid transparent}.btn.uppercase{text-transform:uppercase}.btn.btn-flat{border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border-width:1px}.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125)}.btn:focus{outline:none}.btn.btn-file{position:relative;overflow:hidden}.btn.btn-file > input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;opacity:0;filter:alpha(opacity=0);outline:none;background:white;cursor:inherit;display:block}.btn-default{background-color:#f4f4f4;color:#444;border-color:#ddd}.btn-default:hover,.btn-default:active,.btn-default.hover{background-color:#e7e7e7}.btn-primary{background-color:#3c8dbc;border-color:#367fa9}.btn-primary:hover,.btn-primary:active,.btn-primary.hover{background-color:#367fa9}.btn-success{background-color:#00a65a;border-color:#008d4c}.btn-success:hover,.btn-success:active,.btn-success.hover{background-color:#008d4c}.btn-info{background-color:#00c0ef;border-color:#00acd6}.btn-info:hover,.btn-info:active,.btn-info.hover{background-color:#00acd6}.btn-danger{background-color:#dd4b39;border-color:#d73925}.btn-danger:hover,.btn-danger:active,.btn-danger.hover{background-color:#d73925}.btn-warning{background-color:#f39c12;border-color:#e08e0b}.btn-warning:hover,.btn-warning:active,.btn-warning.hover{background-color:#e08e0b}.btn-outline{border:1px solid #fff;background:transparent;color:#fff}.btn-outline:hover,.btn-outline:focus,.btn-outline:active{color:rgba(255, 255, 255, 0.7);border-color:rgba(255, 255, 255, 0.7)}.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn[class*=bg-]:hover{-webkit-box-shadow:inset 0 0 100px rgba(0, 0, 0, 0.2);box-shadow:inset 0 0 100px rgba(0, 0, 0, 0.2)}.btn-app{border-radius:3px;position:relative;padding:15px 5px;margin:0 0 10px 10px;min-width:80px;height:60px;text-align:center;color:#666;border:1px solid #ddd;background-color:#f4f4f4;font-size:12px}.btn-app > .fa,.btn-app > .glyphicon,.btn-app > .ion{font-size:20px;display:block}.btn-app:hover{background:#f4f4f4;color:#444;border-color:#aaa}.btn-app:active,.btn-app:focus{-webkit-box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125)}.btn-app > .badge{position:absolute;top:-3px;right:-10px;font-size:10px;font-weight:400}.callout{border-radius:3px;margin:0 0 20px 0;padding:15px 30px 15px 15px;border-left:5px solid #eee}.callout a{color:#fff;text-decoration:underline}.callout a:hover{color:#eee}.callout h4{margin-top:0;font-weight:600}.callout p:last-child{margin-bottom:0}.callout code,.callout .highlight{background-color:#fff}.callout.callout-danger{border-color:#c23321}.callout.callout-warning{border-color:#c87f0a}.callout.callout-info{border-color:#0097bc}.callout.callout-success{border-color:#00733e}.alert{border-radius:3px}.alert h4{font-weight:600}.alert .icon{margin-right:10px}.alert .close{color:#000;opacity:.2;filter:alpha(opacity=20)}.alert .close:hover{opacity:.5;filter:alpha(opacity=50)}.alert a{color:#fff;text-decoration:underline}.alert-success{border-color:#008d4c}.alert-danger,.alert-error{border-color:#d73925}.alert-warning{border-color:#e08e0b}.alert-info{border-color:#00acd6}.nav > li > a:hover,.nav > li > a:active,.nav > li > a:focus{color:#444;background:#f7f7f7}.nav-pills > li > a{border-radius:0;border-top:3px solid transparent;color:#444}.nav-pills > li > a > .fa,.nav-pills > li > a > .glyphicon,.nav-pills > li > a > .ion{margin-right:5px}.nav-pills > li.active > a,.nav-pills > li.active > a:hover,.nav-pills > li.active > a:focus{border-top-color:#3c8dbc}.nav-pills > li.active > a{font-weight:600}.nav-stacked > li > a{border-radius:0;border-top:0;border-left:3px solid transparent;color:#444}.nav-stacked > li.active > a,.nav-stacked > li.active > a:hover{background:transparent;color:#444;border-top:0;border-left-color:#3c8dbc}.nav-stacked > li.header{border-bottom:1px solid #ddd;color:#777;margin-bottom:10px;padding:5px 10px;text-transform:uppercase}.nav-tabs-custom{margin-bottom:20px;background:#fff;box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);border-radius:3px}.nav-tabs-custom > .nav-tabs{margin:0;border-bottom-color:#f4f4f4;border-top-right-radius:3px;border-top-left-radius:3px}.nav-tabs-custom > .nav-tabs > li{border-top:3px solid transparent;margin-bottom:-2px;margin-right:5px}.nav-tabs-custom > .nav-tabs > li > a{color:#444;border-radius:0}.nav-tabs-custom > .nav-tabs > li > a.text-muted{color:#999}.nav-tabs-custom > .nav-tabs > li > a,.nav-tabs-custom > .nav-tabs > li > a:hover{background:transparent;margin:0}.nav-tabs-custom > .nav-tabs > li > a:hover{color:#999}.nav-tabs-custom > .nav-tabs > li:not(.active) > a:hover,.nav-tabs-custom > .nav-tabs > li:not(.active) > a:focus,.nav-tabs-custom > .nav-tabs > li:not(.active) > a:active{border-color:transparent}.nav-tabs-custom > .nav-tabs > li.active{border-top-color:#3c8dbc}.nav-tabs-custom > .nav-tabs > li.active > a,.nav-tabs-custom > .nav-tabs > li.active:hover > a{background-color:#fff;color:#444}.nav-tabs-custom > .nav-tabs > li.active > a{border-top-color:transparent;border-left-color:#f4f4f4;border-right-color:#f4f4f4}.nav-tabs-custom > .nav-tabs > li:first-of-type{margin-left:0}.nav-tabs-custom > .nav-tabs > li:first-of-type.active > a{border-left-color:transparent}.nav-tabs-custom > .nav-tabs.pull-right{float:none !important}.nav-tabs-custom > .nav-tabs.pull-right > li{float:right}.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type{margin-right:0}.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type > a{border-left-width:1px}.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a{border-left-color:#f4f4f4;border-right-color:transparent}.nav-tabs-custom > .nav-tabs > li.header{line-height:35px;padding:0 10px;font-size:20px;color:#444}.nav-tabs-custom > .nav-tabs > li.header > .fa,.nav-tabs-custom > .nav-tabs > li.header > .glyphicon,.nav-tabs-custom > .nav-tabs > li.header > .ion{margin-right:5px}.nav-tabs-custom > .tab-content{background:#fff;padding:10px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.nav-tabs-custom .dropdown.open > a:active,.nav-tabs-custom .dropdown.open > a:focus{background:transparent;color:#999}.nav-tabs-custom.tab-primary > .nav-tabs > li.active{border-top-color:#3c8dbc}.nav-tabs-custom.tab-info > .nav-tabs > li.active{border-top-color:#00c0ef}.nav-tabs-custom.tab-danger > .nav-tabs > li.active{border-top-color:#dd4b39}.nav-tabs-custom.tab-warning > .nav-tabs > li.active{border-top-color:#f39c12}.nav-tabs-custom.tab-success > .nav-tabs > li.active{border-top-color:#00a65a}.nav-tabs-custom.tab-default > .nav-tabs > li.active{border-top-color:#d2d6de}.pagination > li > a{background:#fafafa;color:#666}.pagination.pagination-flat > li > a{border-radius:0 !important}.products-list{list-style:none;margin:0;padding:0}.products-list > .item{border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);padding:10px 0;background:#fff}.products-list > .item:before,.products-list > .item:after{content:" ";display:table}.products-list > .item:after{clear:both}.products-list .product-img{float:left}.products-list .product-img img{width:50px;height:50px}.products-list .product-info{margin-left:60px}.products-list .product-title{font-weight:600}.products-list .product-description{display:block;color:#999;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.product-list-in-box > .item{-webkit-box-shadow:none;box-shadow:none;border-radius:0;border-bottom:1px solid #f4f4f4}.product-list-in-box > .item:last-of-type{border-bottom-width:0}.table > thead > tr > th,.table > tbody > tr > th,.table > tfoot > tr > th,.table > thead > tr > td,.table > tbody > tr > td,.table > tfoot > tr > td{border-top:1px solid #f4f4f4}.table > thead > tr > th{border-bottom:2px solid #f4f4f4}.table tr td .progress{margin-top:5px}.table-bordered{border:1px solid #f4f4f4}.table-bordered > thead > tr > th,.table-bordered > tbody > tr > th,.table-bordered > tfoot > tr > th,.table-bordered > thead > tr > td,.table-bordered > tbody > tr > td,.table-bordered > tfoot > tr > td{border:1px solid #f4f4f4}.table-bordered > thead > tr > th,.table-bordered > thead > tr > td{border-bottom-width:2px}.table.no-border,.table.no-border td,.table.no-border th{border:0}table.text-center,table.text-center td,table.text-center th{text-align:center}.table.align th{text-align:left}.table.align td{text-align:right}.label-default{background-color:#d2d6de;color:#444}.direct-chat .box-body{border-bottom-right-radius:0;border-bottom-left-radius:0;position:relative;overflow-x:hidden;padding:0}.direct-chat.chat-pane-open .direct-chat-contacts{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.direct-chat-messages{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);padding:10px;height:250px;overflow:auto}.direct-chat-msg,.direct-chat-text{display:block}.direct-chat-msg{margin-bottom:10px}.direct-chat-msg:before,.direct-chat-msg:after{content:" ";display:table}.direct-chat-msg:after{clear:both}.direct-chat-messages,.direct-chat-contacts{-webkit-transition:-webkit-transform .5s ease-in-out;-moz-transition:-moz-transform .5s ease-in-out;-o-transition:-o-transform .5s ease-in-out;transition:transform .5s ease-in-out}.direct-chat-text{border-radius:5px;position:relative;padding:5px 10px;background:#d2d6de;border:1px solid #d2d6de;margin:5px 0 0 50px;color:#444}.direct-chat-text:after,.direct-chat-text:before{position:absolute;right:100%;top:15px;border:solid transparent;border-right-color:#d2d6de;content:" ";height:0;width:0;pointer-events:none}.direct-chat-text:after{border-width:5px;margin-top:-5px}.direct-chat-text:before{border-width:6px;margin-top:-6px}.right .direct-chat-text{margin-right:50px;margin-left:0}.right .direct-chat-text:after,.right .direct-chat-text:before{right:auto;left:100%;border-right-color:transparent;border-left-color:#d2d6de}.direct-chat-img{border-radius:50%;float:left;width:40px;height:40px}.right .direct-chat-img{float:right}.direct-chat-info{display:block;margin-bottom:2px;font-size:12px}.direct-chat-name{font-weight:600}.direct-chat-timestamp{color:#999}.direct-chat-contacts-open .direct-chat-contacts{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.direct-chat-contacts{-webkit-transform:translate(101%, 0);-ms-transform:translate(101%, 0);-o-transform:translate(101%, 0);transform:translate(101%, 0);position:absolute;top:0;bottom:0;height:250px;width:100%;background:#222d32;color:#fff;overflow:auto}.contacts-list > li{border-bottom:1px solid rgba(0, 0, 0, 0.2);padding:10px;margin:0}.contacts-list > li:before,.contacts-list > li:after{content:" ";display:table}.contacts-list > li:after{clear:both}.contacts-list > li:last-of-type{border-bottom:none}.contacts-list-img{border-radius:50%;width:40px;float:left}.contacts-list-info{margin-left:45px;color:#fff}.contacts-list-name,.contacts-list-status{display:block}.contacts-list-name{font-weight:600}.contacts-list-status{font-size:12px}.contacts-list-date{color:#aaa;font-weight:normal}.contacts-list-msg{color:#999}.direct-chat-danger .right > .direct-chat-text{background:#dd4b39;border-color:#dd4b39;color:#fff}.direct-chat-danger .right > .direct-chat-text:after,.direct-chat-danger .right > .direct-chat-text:before{border-left-color:#dd4b39}.direct-chat-primary .right > .direct-chat-text{background:#3c8dbc;border-color:#3c8dbc;color:#fff}.direct-chat-primary .right > .direct-chat-text:after,.direct-chat-primary .right > .direct-chat-text:before{border-left-color:#3c8dbc}.direct-chat-warning .right > .direct-chat-text{background:#f39c12;border-color:#f39c12;color:#fff}.direct-chat-warning .right > .direct-chat-text:after,.direct-chat-warning .right > .direct-chat-text:before{border-left-color:#f39c12}.direct-chat-info .right > .direct-chat-text{background:#00c0ef;border-color:#00c0ef;color:#fff}.direct-chat-info .right > .direct-chat-text:after,.direct-chat-info .right > .direct-chat-text:before{border-left-color:#00c0ef}.direct-chat-success .right > .direct-chat-text{background:#00a65a;border-color:#00a65a;color:#fff}.direct-chat-success .right > .direct-chat-text:after,.direct-chat-success .right > .direct-chat-text:before{border-left-color:#00a65a}.users-list > li{width:25%;float:left;padding:10px;text-align:center}.users-list > li img{border-radius:50%;max-width:100%;height:auto}.users-list > li > a:hover,.users-list > li > a:hover .users-list-name{color:#999}.users-list-name,.users-list-date{display:block}.users-list-name{font-weight:600;color:#444;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.users-list-date{color:#999;font-size:12px}.carousel-control.left,.carousel-control.right{background-image:none}.carousel-control > .fa{font-size:40px;position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-20px}.modal{background:rgba(0, 0, 0, 0.3)}.modal-content{border-radius:0;-webkit-box-shadow:0 2px 3px rgba(0, 0, 0, 0.125);box-shadow:0 2px 3px rgba(0, 0, 0, 0.125);border:0}@media(min-width: 768px){.modal-content{-webkit-box-shadow:0 2px 3px rgba(0, 0, 0, 0.125);box-shadow:0 2px 3px rgba(0, 0, 0, 0.125)}}.modal-header{border-bottom-color:#f4f4f4}.modal-footer{border-top-color:#f4f4f4}.modal-primary .modal-header,.modal-primary .modal-footer{border-color:#307095}.modal-warning .modal-header,.modal-warning .modal-footer{border-color:#c87f0a}.modal-info .modal-header,.modal-info .modal-footer{border-color:#0097bc}.modal-success .modal-header,.modal-success .modal-footer{border-color:#00733e}.modal-danger .modal-header,.modal-danger .modal-footer{border-color:#c23321}.box-widget{border:none;position:relative}.widget-user .widget-user-header{padding:20px;height:120px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user .widget-user-username{margin-top:0;margin-bottom:5px;font-size:25px;font-weight:300;text-shadow:0 1px 1px rgba(0, 0, 0, 0.2)}.widget-user .widget-user-desc{margin-top:0}.widget-user .widget-user-image{position:absolute;top:65px;left:50%;margin-left:-45px}.widget-user .widget-user-image > img{width:90px;height:auto;border:3px solid #fff}.widget-user .box-footer{padding-top:30px}.widget-user-2 .widget-user-header{padding:20px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user-2 .widget-user-username{margin-top:5px;margin-bottom:5px;font-size:25px;font-weight:300}.widget-user-2 .widget-user-desc{margin-top:0}.widget-user-2 .widget-user-username,.widget-user-2 .widget-user-desc{margin-left:75px}.widget-user-2 .widget-user-image > img{width:65px;height:auto;float:left}.mailbox-messages > .table{margin:0}.mailbox-controls{padding:5px}.mailbox-controls.with-border{border-bottom:1px solid #f4f4f4}.mailbox-read-info{border-bottom:1px solid #f4f4f4;padding:10px}.mailbox-read-info h3{font-size:20px;margin:0}.mailbox-read-info h5{margin:0;padding:5px 0 0 0}.mailbox-read-time{color:#999;font-size:13px}.mailbox-read-message{padding:10px}.mailbox-attachments li{float:left;width:200px;border:1px solid #eee;margin-bottom:10px;margin-right:10px}.mailbox-attachment-name{font-weight:bold;color:#666}.mailbox-attachment-icon,.mailbox-attachment-info,.mailbox-attachment-size{display:block}.mailbox-attachment-info{padding:10px;background:#f4f4f4}.mailbox-attachment-size{color:#999;font-size:12px}.mailbox-attachment-icon{text-align:center;font-size:65px;color:#666;padding:20px 10px}.mailbox-attachment-icon.has-img{padding:0}.mailbox-attachment-icon.has-img > img{max-width:100%;height:auto}.lockscreen{background:#d2d6de}.lockscreen-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.lockscreen-logo a{color:#444}.lockscreen-wrapper{max-width:400px;margin:0 auto;margin-top:10%}.lockscreen .lockscreen-name{text-align:center;font-weight:600}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image > img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:10px}.login-logo,.register-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.login-logo a,.register-logo a{color:#444}.login-page,.register-page{background:#d2d6de}.login-box,.register-box{width:360px;margin:7% auto}@media(max-width: 768px){.login-box,.register-box{width:90%;margin-top:20px}}.login-box-body,.register-box-body{background:#fff;padding:20px;border-top:0;color:#666}.login-box-body .form-control-feedback,.register-box-body .form-control-feedback{color:#777}.login-box-msg,.register-box-msg{margin:0;text-align:center;padding:0 20px 20px 20px}.social-auth-links{margin:10px 0}.error-page{width:600px;margin:20px auto 0 auto}@media(max-width: 991px){.error-page{width:100%}}.error-page > .headline{float:left;font-size:100px;font-weight:300}@media(max-width: 991px){.error-page > .headline{float:none;text-align:center}}.error-page > .error-content{margin-left:190px;display:block}@media(max-width: 991px){.error-page > .error-content{margin-left:0}}.error-page > .error-content > h3{font-weight:300;font-size:25px}@media(max-width: 991px){.error-page > .error-content > h3{text-align:center}}.invoice{position:relative;background:#fff;border:1px solid #f4f4f4;padding:20px;margin:10px 25px}.invoice-title{margin-top:0}.profile-user-img{margin:0 auto;width:100px;padding:3px;border:3px solid #d2d6de}.profile-username{font-size:21px;margin-top:5px}.post{border-bottom:1px solid #d2d6de;margin-bottom:15px;padding-bottom:15px;color:#666}.post:last-of-type{border-bottom:0;margin-bottom:0;padding-bottom:0}.post .user-block{margin-bottom:15px}.btn-social{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-social > :first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0, 0, 0, 0.2)}.btn-social.btn-lg{padding-left:61px}.btn-social.btn-lg > :first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social.btn-sm{padding-left:38px}.btn-social.btn-sm > :first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social.btn-xs{padding-left:30px}.btn-social.btn-xs > :first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:34px;width:34px;padding:0}.btn-social-icon > :first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0, 0, 0, 0.2)}.btn-social-icon.btn-lg{padding-left:61px}.btn-social-icon.btn-lg > :first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social-icon.btn-sm{padding-left:38px}.btn-social-icon.btn-sm > :first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social-icon.btn-xs{padding-left:30px}.btn-social-icon.btn-xs > :first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon > :first-child{border:none;text-align:center;width:100%}.btn-social-icon.btn-lg{height:45px;width:45px;padding-left:0;padding-right:0}.btn-social-icon.btn-sm{height:30px;width:30px;padding-left:0;padding-right:0}.btn-social-icon.btn-xs{height:22px;width:22px;padding-left:0;padding-right:0}.btn-adn{color:#fff;background-color:#d87a68;border-color:rgba(0, 0, 0, 0.2)}.btn-adn:focus,.btn-adn.focus{color:#fff;background-color:#ce563f;border-color:rgba(0, 0, 0, 0.2)}.btn-adn:hover{color:#fff;background-color:#ce563f;border-color:rgba(0, 0, 0, 0.2)}.btn-adn:active,.btn-adn.active,.open > .dropdown-toggle.btn-adn{color:#fff;background-color:#ce563f;border-color:rgba(0, 0, 0, 0.2)}.btn-adn:active,.btn-adn.active,.open > .dropdown-toggle.btn-adn{background-image:none}.btn-adn .badge{color:#d87a68;background-color:#fff}.btn-bitbucket{color:#fff;background-color:#205081;border-color:rgba(0, 0, 0, 0.2)}.btn-bitbucket:focus,.btn-bitbucket.focus{color:#fff;background-color:#163758;border-color:rgba(0, 0, 0, 0.2)}.btn-bitbucket:hover{color:#fff;background-color:#163758;border-color:rgba(0, 0, 0, 0.2)}.btn-bitbucket:active,.btn-bitbucket.active,.open > .dropdown-toggle.btn-bitbucket{color:#fff;background-color:#163758;border-color:rgba(0, 0, 0, 0.2)}.btn-bitbucket:active,.btn-bitbucket.active,.open > .dropdown-toggle.btn-bitbucket{background-image:none}.btn-bitbucket .badge{color:#205081;background-color:#fff}.btn-dropbox{color:#fff;background-color:#1087dd;border-color:rgba(0, 0, 0, 0.2)}.btn-dropbox:focus,.btn-dropbox.focus{color:#fff;background-color:#0d6aad;border-color:rgba(0, 0, 0, 0.2)}.btn-dropbox:hover{color:#fff;background-color:#0d6aad;border-color:rgba(0, 0, 0, 0.2)}.btn-dropbox:active,.btn-dropbox.active,.open > .dropdown-toggle.btn-dropbox{color:#fff;background-color:#0d6aad;border-color:rgba(0, 0, 0, 0.2)}.btn-dropbox:active,.btn-dropbox.active,.open > .dropdown-toggle.btn-dropbox{background-image:none}.btn-dropbox .badge{color:#1087dd;background-color:#fff}.btn-facebook{color:#fff;background-color:#3b5998;border-color:rgba(0, 0, 0, 0.2)}.btn-facebook:focus,.btn-facebook.focus{color:#fff;background-color:#2d4373;border-color:rgba(0, 0, 0, 0.2)}.btn-facebook:hover{color:#fff;background-color:#2d4373;border-color:rgba(0, 0, 0, 0.2)}.btn-facebook:active,.btn-facebook.active,.open > .dropdown-toggle.btn-facebook{color:#fff;background-color:#2d4373;border-color:rgba(0, 0, 0, 0.2)}.btn-facebook:active,.btn-facebook.active,.open > .dropdown-toggle.btn-facebook{background-image:none}.btn-facebook .badge{color:#3b5998;background-color:#fff}.btn-flickr{color:#fff;background-color:#ff0084;border-color:rgba(0, 0, 0, 0.2)}.btn-flickr:focus,.btn-flickr.focus{color:#fff;background-color:#cc006a;border-color:rgba(0, 0, 0, 0.2)}.btn-flickr:hover{color:#fff;background-color:#cc006a;border-color:rgba(0, 0, 0, 0.2)}.btn-flickr:active,.btn-flickr.active,.open > .dropdown-toggle.btn-flickr{color:#fff;background-color:#cc006a;border-color:rgba(0, 0, 0, 0.2)}.btn-flickr:active,.btn-flickr.active,.open > .dropdown-toggle.btn-flickr{background-image:none}.btn-flickr .badge{color:#ff0084;background-color:#fff}.btn-foursquare{color:#fff;background-color:#f94877;border-color:rgba(0, 0, 0, 0.2)}.btn-foursquare:focus,.btn-foursquare.focus{color:#fff;background-color:#f71752;border-color:rgba(0, 0, 0, 0.2)}.btn-foursquare:hover{color:#fff;background-color:#f71752;border-color:rgba(0, 0, 0, 0.2)}.btn-foursquare:active,.btn-foursquare.active,.open > .dropdown-toggle.btn-foursquare{color:#fff;background-color:#f71752;border-color:rgba(0, 0, 0, 0.2)}.btn-foursquare:active,.btn-foursquare.active,.open > .dropdown-toggle.btn-foursquare{background-image:none}.btn-foursquare .badge{color:#f94877;background-color:#fff}.btn-github{color:#fff;background-color:#444;border-color:rgba(0, 0, 0, 0.2)}.btn-github:focus,.btn-github.focus{color:#fff;background-color:#2b2b2b;border-color:rgba(0, 0, 0, 0.2)}.btn-github:hover{color:#fff;background-color:#2b2b2b;border-color:rgba(0, 0, 0, 0.2)}.btn-github:active,.btn-github.active,.open > .dropdown-toggle.btn-github{color:#fff;background-color:#2b2b2b;border-color:rgba(0, 0, 0, 0.2)}.btn-github:active,.btn-github.active,.open > .dropdown-toggle.btn-github{background-image:none}.btn-github .badge{color:#444;background-color:#fff}.btn-google{color:#fff;background-color:#dd4b39;border-color:rgba(0, 0, 0, 0.2)}.btn-google:focus,.btn-google.focus{color:#fff;background-color:#c23321;border-color:rgba(0, 0, 0, 0.2)}.btn-google:hover{color:#fff;background-color:#c23321;border-color:rgba(0, 0, 0, 0.2)}.btn-google:active,.btn-google.active,.open > .dropdown-toggle.btn-google{color:#fff;background-color:#c23321;border-color:rgba(0, 0, 0, 0.2)}.btn-google:active,.btn-google.active,.open > .dropdown-toggle.btn-google{background-image:none}.btn-google .badge{color:#dd4b39;background-color:#fff}.btn-instagram{color:#fff;background-color:#3f729b;border-color:rgba(0, 0, 0, 0.2)}.btn-instagram:focus,.btn-instagram.focus{color:#fff;background-color:#305777;border-color:rgba(0, 0, 0, 0.2)}.btn-instagram:hover{color:#fff;background-color:#305777;border-color:rgba(0, 0, 0, 0.2)}.btn-instagram:active,.btn-instagram.active,.open > .dropdown-toggle.btn-instagram{color:#fff;background-color:#305777;border-color:rgba(0, 0, 0, 0.2)}.btn-instagram:active,.btn-instagram.active,.open > .dropdown-toggle.btn-instagram{background-image:none}.btn-instagram .badge{color:#3f729b;background-color:#fff}.btn-linkedin{color:#fff;background-color:#007bb6;border-color:rgba(0, 0, 0, 0.2)}.btn-linkedin:focus,.btn-linkedin.focus{color:#fff;background-color:#005983;border-color:rgba(0, 0, 0, 0.2)}.btn-linkedin:hover{color:#fff;background-color:#005983;border-color:rgba(0, 0, 0, 0.2)}.btn-linkedin:active,.btn-linkedin.active,.open > .dropdown-toggle.btn-linkedin{color:#fff;background-color:#005983;border-color:rgba(0, 0, 0, 0.2)}.btn-linkedin:active,.btn-linkedin.active,.open > .dropdown-toggle.btn-linkedin{background-image:none}.btn-linkedin .badge{color:#007bb6;background-color:#fff}.btn-microsoft{color:#fff;background-color:#2672ec;border-color:rgba(0, 0, 0, 0.2)}.btn-microsoft:focus,.btn-microsoft.focus{color:#fff;background-color:#125acd;border-color:rgba(0, 0, 0, 0.2)}.btn-microsoft:hover{color:#fff;background-color:#125acd;border-color:rgba(0, 0, 0, 0.2)}.btn-microsoft:active,.btn-microsoft.active,.open > .dropdown-toggle.btn-microsoft{color:#fff;background-color:#125acd;border-color:rgba(0, 0, 0, 0.2)}.btn-microsoft:active,.btn-microsoft.active,.open > .dropdown-toggle.btn-microsoft{background-image:none}.btn-microsoft .badge{color:#2672ec;background-color:#fff}.btn-openid{color:#fff;background-color:#f7931e;border-color:rgba(0, 0, 0, 0.2)}.btn-openid:focus,.btn-openid.focus{color:#fff;background-color:#da7908;border-color:rgba(0, 0, 0, 0.2)}.btn-openid:hover{color:#fff;background-color:#da7908;border-color:rgba(0, 0, 0, 0.2)}.btn-openid:active,.btn-openid.active,.open > .dropdown-toggle.btn-openid{color:#fff;background-color:#da7908;border-color:rgba(0, 0, 0, 0.2)}.btn-openid:active,.btn-openid.active,.open > .dropdown-toggle.btn-openid{background-image:none}.btn-openid .badge{color:#f7931e;background-color:#fff}.btn-pinterest{color:#fff;background-color:#cb2027;border-color:rgba(0, 0, 0, 0.2)}.btn-pinterest:focus,.btn-pinterest.focus{color:#fff;background-color:#9f191f;border-color:rgba(0, 0, 0, 0.2)}.btn-pinterest:hover{color:#fff;background-color:#9f191f;border-color:rgba(0, 0, 0, 0.2)}.btn-pinterest:active,.btn-pinterest.active,.open > .dropdown-toggle.btn-pinterest{color:#fff;background-color:#9f191f;border-color:rgba(0, 0, 0, 0.2)}.btn-pinterest:active,.btn-pinterest.active,.open > .dropdown-toggle.btn-pinterest{background-image:none}.btn-pinterest .badge{color:#cb2027;background-color:#fff}.btn-reddit{color:#000;background-color:#eff7ff;border-color:rgba(0, 0, 0, 0.2)}.btn-reddit:focus,.btn-reddit.focus{color:#000;background-color:#bcddff;border-color:rgba(0, 0, 0, 0.2)}.btn-reddit:hover{color:#000;background-color:#bcddff;border-color:rgba(0, 0, 0, 0.2)}.btn-reddit:active,.btn-reddit.active,.open > .dropdown-toggle.btn-reddit{color:#000;background-color:#bcddff;border-color:rgba(0, 0, 0, 0.2)}.btn-reddit:active,.btn-reddit.active,.open > .dropdown-toggle.btn-reddit{background-image:none}.btn-reddit .badge{color:#eff7ff;background-color:#000}.btn-soundcloud{color:#fff;background-color:#f50;border-color:rgba(0, 0, 0, 0.2)}.btn-soundcloud:focus,.btn-soundcloud.focus{color:#fff;background-color:#c40;border-color:rgba(0, 0, 0, 0.2)}.btn-soundcloud:hover{color:#fff;background-color:#c40;border-color:rgba(0, 0, 0, 0.2)}.btn-soundcloud:active,.btn-soundcloud.active,.open > .dropdown-toggle.btn-soundcloud{color:#fff;background-color:#c40;border-color:rgba(0, 0, 0, 0.2)}.btn-soundcloud:active,.btn-soundcloud.active,.open > .dropdown-toggle.btn-soundcloud{background-image:none}.btn-soundcloud .badge{color:#f50;background-color:#fff}.btn-tumblr{color:#fff;background-color:#2c4762;border-color:rgba(0, 0, 0, 0.2)}.btn-tumblr:focus,.btn-tumblr.focus{color:#fff;background-color:#1c2d3f;border-color:rgba(0, 0, 0, 0.2)}.btn-tumblr:hover{color:#fff;background-color:#1c2d3f;border-color:rgba(0, 0, 0, 0.2)}.btn-tumblr:active,.btn-tumblr.active,.open > .dropdown-toggle.btn-tumblr{color:#fff;background-color:#1c2d3f;border-color:rgba(0, 0, 0, 0.2)}.btn-tumblr:active,.btn-tumblr.active,.open > .dropdown-toggle.btn-tumblr{background-image:none}.btn-tumblr .badge{color:#2c4762;background-color:#fff}.btn-twitter{color:#fff;background-color:#55acee;border-color:rgba(0, 0, 0, 0.2)}.btn-twitter:focus,.btn-twitter.focus{color:#fff;background-color:#2795e9;border-color:rgba(0, 0, 0, 0.2)}.btn-twitter:hover{color:#fff;background-color:#2795e9;border-color:rgba(0, 0, 0, 0.2)}.btn-twitter:active,.btn-twitter.active,.open > .dropdown-toggle.btn-twitter{color:#fff;background-color:#2795e9;border-color:rgba(0, 0, 0, 0.2)}.btn-twitter:active,.btn-twitter.active,.open > .dropdown-toggle.btn-twitter{background-image:none}.btn-twitter .badge{color:#55acee;background-color:#fff}.btn-vimeo{color:#fff;background-color:#1ab7ea;border-color:rgba(0, 0, 0, 0.2)}.btn-vimeo:focus,.btn-vimeo.focus{color:#fff;background-color:#1295bf;border-color:rgba(0, 0, 0, 0.2)}.btn-vimeo:hover{color:#fff;background-color:#1295bf;border-color:rgba(0, 0, 0, 0.2)}.btn-vimeo:active,.btn-vimeo.active,.open > .dropdown-toggle.btn-vimeo{color:#fff;background-color:#1295bf;border-color:rgba(0, 0, 0, 0.2)}.btn-vimeo:active,.btn-vimeo.active,.open > .dropdown-toggle.btn-vimeo{background-image:none}.btn-vimeo .badge{color:#1ab7ea;background-color:#fff}.btn-vk{color:#fff;background-color:#587ea3;border-color:rgba(0, 0, 0, 0.2)}.btn-vk:focus,.btn-vk.focus{color:#fff;background-color:#466482;border-color:rgba(0, 0, 0, 0.2)}.btn-vk:hover{color:#fff;background-color:#466482;border-color:rgba(0, 0, 0, 0.2)}.btn-vk:active,.btn-vk.active,.open > .dropdown-toggle.btn-vk{color:#fff;background-color:#466482;border-color:rgba(0, 0, 0, 0.2)}.btn-vk:active,.btn-vk.active,.open > .dropdown-toggle.btn-vk{background-image:none}.btn-vk .badge{color:#587ea3;background-color:#fff}.btn-yahoo{color:#fff;background-color:#720e9e;border-color:rgba(0, 0, 0, 0.2)}.btn-yahoo:focus,.btn-yahoo.focus{color:#fff;background-color:#500a6f;border-color:rgba(0, 0, 0, 0.2)}.btn-yahoo:hover{color:#fff;background-color:#500a6f;border-color:rgba(0, 0, 0, 0.2)}.btn-yahoo:active,.btn-yahoo.active,.open > .dropdown-toggle.btn-yahoo{color:#fff;background-color:#500a6f;border-color:rgba(0, 0, 0, 0.2)}.btn-yahoo:active,.btn-yahoo.active,.open > .dropdown-toggle.btn-yahoo{background-image:none}.btn-yahoo .badge{color:#720e9e;background-color:#fff}.fc-button{background:#f4f4f4;background-image:none;color:#444;border-color:#ddd;border-bottom-color:#ddd}.fc-button:hover,.fc-button:active,.fc-button.hover{background-color:#e9e9e9}.fc-header-title h2{font-size:15px;line-height:1.6em;color:#666;margin-left:10px}.fc-header-right{padding-right:10px}.fc-header-left{padding-left:10px}.fc-widget-header{background:#fafafa}.fc-grid{width:100%;border:0}.fc-widget-header:first-of-type,.fc-widget-content:first-of-type{border-left:0;border-right:0}.fc-widget-header:last-of-type,.fc-widget-content:last-of-type{border-right:0}.fc-toolbar{padding:10px;margin:0}.fc-day-number{font-size:20px;font-weight:300;padding-right:10px}.fc-color-picker{list-style:none;margin:0;padding:0}.fc-color-picker > li{float:left;font-size:30px;margin-right:5px;line-height:30px}.fc-color-picker > li .fa{-webkit-transition:-webkit-transform linear .3s;-moz-transition:-moz-transform linear .3s;-o-transition:-o-transform linear .3s;transition:transform linear .3s}.fc-color-picker > li .fa:hover{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);-o-transform:rotate(30deg);transform:rotate(30deg)}#add-new-event{-webkit-transition:all linear .3s;-o-transition:all linear .3s;transition:all linear .3s}.external-event{padding:5px 10px;font-weight:bold;margin-bottom:4px;box-shadow:0 1px 1px rgba(0, 0, 0, 0.1);text-shadow:0 1px 1px rgba(0, 0, 0, 0.1);border-radius:3px;cursor:move}.external-event:hover{box-shadow:inset 0 0 90px rgba(0, 0, 0, 0.2)}.select2-container--default.select2-container--focus,.select2-selection.select2-container--focus,.select2-container--default:focus,.select2-selection:focus,.select2-container--default:active,.select2-selection:active{outline:none}.select2-container--default .select2-selection--single,.select2-selection .select2-selection--single{border:1px solid #d2d6de;border-radius:0;padding:6px 12px;height:34px}.select2-container--default.select2-container--open{border-color:#3c8dbc}.select2-dropdown{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#3c8dbc;color:white}.select2-results__option{padding:6px 12px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{padding-left:0;padding-right:0;height:auto;margin-top:-4px}.select2-container[dir=rtl] .select2-selection--single .select2-selection__rendered{padding-right:6px;padding-left:20px}.select2-container--default .select2-selection--single .select2-selection__arrow{height:28px;right:3px}.select2-container--default .select2-selection--single .select2-selection__arrow b{margin-top:0}.select2-dropdown .select2-search__field,.select2-search--inline .select2-search__field{border:1px solid #d2d6de}.select2-dropdown .select2-search__field:focus,.select2-search--inline .select2-search__field:focus{outline:none;border:1px solid #3c8dbc}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option[aria-selected=true],.select2-container--default .select2-results__option[aria-selected=true]:hover{color:#444}.select2-container--default .select2-selection--multiple{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-selection--multiple:focus{border-color:#3c8dbc}.select2-container--default.select2-container--focus .select2-selection--multiple{border-color:#d2d6de}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#3c8dbc;border-color:#367fa9;padding:1px 10px;color:#fff}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{margin-right:5px;color:rgba(255, 255, 255, 0.7)}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#fff}.select2-container .select2-selection--single .select2-selection__rendered{padding-right:10px}.pad{padding:10px}.margin{margin:10px}.margin-bottom{margin-bottom:20px}.margin-bottom-none{margin-bottom:0}.margin-r-5{margin-right:5px}.inline{display:inline}.description-block{display:block;margin:10px 0;text-align:center}.description-block.margin-bottom{margin-bottom:25px}.description-block > .description-header{margin:0;padding:0;font-weight:600;font-size:16px}.description-block > .description-text{text-transform:uppercase}.bg-red,.bg-yellow,.bg-aqua,.bg-blue,.bg-light-blue,.bg-green,.bg-navy,.bg-teal,.bg-olive,.bg-lime,.bg-orange,.bg-fuchsia,.bg-purple,.bg-maroon,.bg-black,.bg-red-active,.bg-yellow-active,.bg-aqua-active,.bg-blue-active,.bg-light-blue-active,.bg-green-active,.bg-navy-active,.bg-teal-active,.bg-olive-active,.bg-lime-active,.bg-orange-active,.bg-fuchsia-active,.bg-purple-active,.bg-maroon-active,.bg-black-active,.callout.callout-danger,.callout.callout-warning,.callout.callout-info,.callout.callout-success,.alert-success,.alert-danger,.alert-error,.alert-warning,.alert-info,.label-danger,.label-info,.label-warning,.label-primary,.label-success,.modal-primary .modal-body,.modal-primary .modal-header,.modal-primary .modal-footer,.modal-warning .modal-body,.modal-warning .modal-header,.modal-warning .modal-footer,.modal-info .modal-body,.modal-info .modal-header,.modal-info .modal-footer,.modal-success .modal-body,.modal-success .modal-header,.modal-success .modal-footer,.modal-danger .modal-body,.modal-danger .modal-header,.modal-danger .modal-footer{color:#fff !important}.bg-gray{color:#000;background-color:#d2d6de !important}.bg-gray-light{background-color:#f7f7f7}.bg-black{background-color:#111 !important}.bg-red,.callout.callout-danger,.alert-danger,.alert-error,.label-danger,.modal-danger .modal-body{background-color:#dd4b39 !important}.bg-yellow,.callout.callout-warning,.alert-warning,.label-warning,.modal-warning .modal-body{background-color:#f39c12 !important}.bg-aqua,.callout.callout-info,.alert-info,.label-info,.modal-info .modal-body{background-color:#00c0ef !important}.bg-blue{background-color:#0073b7 !important}.bg-light-blue,.label-primary,.modal-primary .modal-body{background-color:#3c8dbc !important}.bg-green,.callout.callout-success,.alert-success,.label-success,.modal-success .modal-body{background-color:#00a65a !important}.bg-navy{background-color:#001f3f !important}.bg-teal{background-color:#39cccc !important}.bg-olive{background-color:#3d9970 !important}.bg-lime{background-color:#01ff70 !important}.bg-orange{background-color:#ff851b !important}.bg-fuchsia{background-color:#f012be !important}.bg-purple{background-color:#605ca8 !important}.bg-maroon{background-color:#d81b60 !important}.bg-gray-active{color:#000;background-color:#b5bbc8 !important}.bg-black-active{background-color:#000 !important}.bg-red-active,.modal-danger .modal-header,.modal-danger .modal-footer{background-color:#d33724 !important}.bg-yellow-active,.modal-warning .modal-header,.modal-warning .modal-footer{background-color:#db8b0b !important}.bg-aqua-active,.modal-info .modal-header,.modal-info .modal-footer{background-color:#00a7d0 !important}.bg-blue-active{background-color:#005384 !important}.bg-light-blue-active,.modal-primary .modal-header,.modal-primary .modal-footer{background-color:#357ca5 !important}.bg-green-active,.modal-success .modal-header,.modal-success .modal-footer{background-color:#008d4c !important}.bg-navy-active{background-color:#001a35 !important}.bg-teal-active{background-color:#30bbbb !important}.bg-olive-active{background-color:#368763 !important}.bg-lime-active{background-color:#00e765 !important}.bg-orange-active{background-color:#ff7701 !important}.bg-fuchsia-active{background-color:#db0ead !important}.bg-purple-active{background-color:#555299 !important}.bg-maroon-active{background-color:#ca195a !important}[class^=bg-].disabled{opacity:.65;filter:alpha(opacity=65)}.text-red{color:#dd4b39 !important}.text-yellow{color:#f39c12 !important}.text-aqua{color:#00c0ef !important}.text-blue{color:#0073b7 !important}.text-black{color:#111 !important}.text-light-blue{color:#3c8dbc !important}.text-green{color:#00a65a !important}.text-gray{color:#d2d6de !important}.text-navy{color:#001f3f !important}.text-teal{color:#39cccc !important}.text-olive{color:#3d9970 !important}.text-lime{color:#01ff70 !important}.text-orange{color:#ff851b !important}.text-fuchsia{color:#f012be !important}.text-purple{color:#605ca8 !important}.text-maroon{color:#d81b60 !important}.link-muted{color:#7a869d}.link-muted:hover,.link-muted:focus{color:#606c84}.link-black{color:#666}.link-black:hover,.link-black:focus{color:#999}.hide{display:none !important}.no-border{border:0 !important}.no-padding{padding:0 !important}.no-margin{margin:0 !important}.no-shadow{box-shadow:none !important}.list-unstyled,.chart-legend,.contacts-list,.users-list,.mailbox-attachments{list-style:none;margin:0;padding:0}.list-group-unbordered > .list-group-item{border-left:0;border-right:0;border-radius:0;padding-left:0;padding-right:0}.flat{border-radius:0 !important}.text-bold,.text-bold.table td,.text-bold.table th{font-weight:700}.text-sm{font-size:12px}.jqstooltip{padding:5px !important;width:auto !important;height:auto !important}.bg-teal-gradient{background:#39cccc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #39cccc), color-stop(1, #7adddd)) !important;background:-ms-linear-gradient(bottom, #39cccc, #7adddd) !important;background:-moz-linear-gradient(center bottom, #39cccc 0%, #7adddd 100%) !important;background:-o-linear-gradient(#7adddd, #39cccc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#7adddd", endColorstr="#39cccc", GradientType=0) !important;color:#fff}.bg-light-blue-gradient{background:#3c8dbc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #3c8dbc), color-stop(1, #67a8ce)) !important;background:-ms-linear-gradient(bottom, #3c8dbc, #67a8ce) !important;background:-moz-linear-gradient(center bottom, #3c8dbc 0%, #67a8ce 100%) !important;background:-o-linear-gradient(#67a8ce, #3c8dbc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#67a8ce", endColorstr="#3c8dbc", GradientType=0) !important;color:#fff}.bg-blue-gradient{background:#0073b7 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #0073b7), color-stop(1, #0089db)) !important;background:-ms-linear-gradient(bottom, #0073b7, #0089db) !important;background:-moz-linear-gradient(center bottom, #0073b7 0%, #0089db 100%) !important;background:-o-linear-gradient(#0089db, #0073b7) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#0089db", endColorstr="#0073b7", GradientType=0) !important;color:#fff}.bg-aqua-gradient{background:#00c0ef !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00c0ef), color-stop(1, #14d1ff)) !important;background:-ms-linear-gradient(bottom, #00c0ef, #14d1ff) !important;background:-moz-linear-gradient(center bottom, #00c0ef 0%, #14d1ff 100%) !important;background:-o-linear-gradient(#14d1ff, #00c0ef) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#14d1ff", endColorstr="#00c0ef", GradientType=0) !important;color:#fff}.bg-yellow-gradient{background:#f39c12 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #f39c12), color-stop(1, #f7bc60)) !important;background:-ms-linear-gradient(bottom, #f39c12, #f7bc60) !important;background:-moz-linear-gradient(center bottom, #f39c12 0%, #f7bc60 100%) !important;background:-o-linear-gradient(#f7bc60, #f39c12) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#f7bc60", endColorstr="#f39c12", GradientType=0) !important;color:#fff}.bg-purple-gradient{background:#605ca8 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #605ca8), color-stop(1, #9491c4)) !important;background:-ms-linear-gradient(bottom, #605ca8, #9491c4) !important;background:-moz-linear-gradient(center bottom, #605ca8 0%, #9491c4 100%) !important;background:-o-linear-gradient(#9491c4, #605ca8) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#9491c4", endColorstr="#605ca8", GradientType=0) !important;color:#fff}.bg-green-gradient{background:#00a65a !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00a65a), color-stop(1, #00ca6d)) !important;background:-ms-linear-gradient(bottom, #00a65a, #00ca6d) !important;background:-moz-linear-gradient(center bottom, #00a65a 0%, #00ca6d 100%) !important;background:-o-linear-gradient(#00ca6d, #00a65a) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ca6d", endColorstr="#00a65a", GradientType=0) !important;color:#fff}.bg-red-gradient{background:#dd4b39 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #dd4b39), color-stop(1, #e47365)) !important;background:-ms-linear-gradient(bottom, #dd4b39, #e47365) !important;background:-moz-linear-gradient(center bottom, #dd4b39 0%, #e47365 100%) !important;background:-o-linear-gradient(#e47365, #dd4b39) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#e47365", endColorstr="#dd4b39", GradientType=0) !important;color:#fff}.bg-black-gradient{background:#111 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #111111), color-stop(1, #2b2b2b)) !important;background:-ms-linear-gradient(bottom, #111111, #2b2b2b) !important;background:-moz-linear-gradient(center bottom, #111111 0%, #2b2b2b 100%) !important;background:-o-linear-gradient(#2b2b2b, #111111) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#2b2b2b", endColorstr="#111111", GradientType=0) !important;color:#fff}.bg-maroon-gradient{background:#d81b60 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #d81b60), color-stop(1, #e73f7c)) !important;background:-ms-linear-gradient(bottom, #d81b60, #e73f7c) !important;background:-moz-linear-gradient(center bottom, #d81b60 0%, #e73f7c 100%) !important;background:-o-linear-gradient(#e73f7c, #d81b60) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#e73f7c", endColorstr="#d81b60", GradientType=0) !important;color:#fff}.description-block .description-icon{font-size:16px}.no-pad-top{padding-top:0}.position-static{position:static !important}.list-header{font-size:15px;padding:10px 4px;font-weight:bold;color:#666}.list-seperator{height:1px;background:#f4f4f4;margin:15px 0 9px 0}.list-link > a{padding:4px;color:#777}.list-link > a:hover{color:#222}.font-light{font-weight:300}.user-block:before,.user-block:after{content:" ";display:table}.user-block:after{clear:both}.user-block img{width:40px;height:40px;float:left}.user-block .username,.user-block .description,.user-block .comment{display:block;margin-left:50px}.user-block .username{font-size:16px;font-weight:600}.user-block .description{color:#999;font-size:13px}.user-block.user-block-sm .username,.user-block.user-block-sm .description,.user-block.user-block-sm .comment{margin-left:40px}.user-block.user-block-sm .username{font-size:14px}.img-sm,.img-md,.img-lg,.box-comments .box-comment img,.user-block.user-block-sm img{float:left}.img-sm,.box-comments .box-comment img,.user-block.user-block-sm img{width:30px !important;height:30px !important}.img-sm + .img-push{margin-left:40px}.img-md{width:60px;height:60px}.img-md + .img-push{margin-left:70px}.img-lg{width:100px;height:100px}.img-lg + .img-push{margin-left:110px}.img-bordered{border:3px solid #d2d6de;padding:3px}.img-bordered-sm{border:2px solid #d2d6de;padding:2px}.attachment-block{border:1px solid #f4f4f4;padding:5px;margin-bottom:10px;background:#f7f7f7}.attachment-block .attachment-img{max-width:100px;max-height:100px;height:auto;float:left}.attachment-block .attachment-pushed{margin-left:110px}.attachment-block .attachment-heading{margin:0}.attachment-block .attachment-text{color:#555}.connectedSortable{min-height:100px}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sort-highlight{background:#f4f4f4;border:1px dashed #ddd;margin-bottom:10px}.full-opacity-hover{opacity:.65;filter:alpha(opacity=65)}.full-opacity-hover:hover{opacity:1;filter:alpha(opacity=100)}.chart{position:relative;overflow:hidden;width:100%}.chart svg,.chart canvas{width:100% !important}@media print{.no-print,.main-sidebar,.left-side,.main-header,.content-header{display:none !important}.content-wrapper,.right-side,.main-footer{margin-left:0 !important;min-height:0 !important;-webkit-transform:translate(0, 0) !important;-ms-transform:translate(0, 0) !important;-o-transform:translate(0, 0) !important;transform:translate(0, 0) !important}.fixed .content-wrapper,.fixed .right-side{padding-top:0 !important}.invoice{width:100%;border:0;margin:0;padding:0}.invoice-col{float:left;width:33.3333333%}.table-responsive{overflow:auto}.table-responsive > .table tr th,.table-responsive > .table tr td{white-space:normal !important}}/*# sourceMappingURL=AdminLTE.min.css.map */ diff --git a/smash/web/static/js/daily_planning.js b/smash/web/static/js/daily_planning.js index b2ce87f76f9f15d1a8725614d3e3630829f12766..1c02d38cb2652d73ebe3cee1c847d4bb2cb7e873 100644 --- a/smash/web/static/js/daily_planning.js +++ b/smash/web/static/js/daily_planning.js @@ -260,148 +260,146 @@ function remove_event(event) { add_event(event, event.color, event.subject_id, event.location_id, boxBody); } -$(document).ready(function () { - $('#calendar').fullCalendar({ +function addDailyPlanningCalendar(calendar_selector, replace_all, calendar_dict_props){ + + var customButtons = { + datePickerButton: { + text: 'select', + click: function () { + var $btnCustom = $('.fc-datePickerButton-button'); + if ($(".calendar-datepicker").length > 0) { + $(".calendar-datepicker").remove(); + } + else { + $btnCustom.after('<div class="calendar-datepicker"/>'); + $(".calendar-datepicker").datepicker().on('changeDate', function (ev) { + $(calendar_selector).fullCalendar('gotoDate', ev.date); + $(".calendar-datepicker").remove(); + }); + } + } + }, + save: { + text: 'Save', + click: function () { + calendarEvents = $(calendar_selector).fullCalendar('clientEvents'); + eventsToPersist = []; + var saveButton = $(".fc-save-button"); + var currentBorder = saveButton.css('border-color'); + $.each(calendarEvents, function (i, calendar_event) { + if (calendar_event.rendering !== "background") { + eventsToPersist.push({ + 'link_id': calendar_event.link_id, + 'appointment_id': calendar_event.appointment_id, + 'link_who': parseInt(calendar_event.resourceId), + 'start': calendar_event.start.format() + }); + if (calendar_event.link_id !== undefined) { + var index = eventsCleared.indexOf(calendar_event.link_id); + if (index > -1) { + eventsCleared.splice(index, 1); + } + } else { + var index = appointmentsCleared.indexOf(calendar_event.appointment_id); + if (index > -1) { + appointmentsCleared.splice(index, 1); + } + } + } + }); + $.post({ + url: events_url, + data: { + events_to_persist: JSON.stringify(eventsToPersist), + events_to_clear: JSON.stringify(eventsCleared), + appointments_to_clear: JSON.stringify(appointmentsCleared) + }, + dataType: "json" + }).done(function (data) { + + saveButton.css('border-color', 'green'); + setTimeout(function () { + saveButton.css('border-color', currentBorder); + }, 200); + }).error(function (data) { + + console.log(data); + saveButton.css('border-color', 'red'); + showErrorInfo("There was an unexpected problem with saving data. " + "Please contact administrators."); + setTimeout(function () { + saveButton.delay(200).css('border-color', currentBorder); + }, 200); + }); + } + }, + clear: { + text: 'Clear', + click: function () { + calendarEvents = $(calendar_selector).fullCalendar('clientEvents'); + $.each(calendarEvents, function (i, calendar_event) { + remove_event(calendar_event); + }); + } + }, + toPdf: { + text: 'PDF', + click: function () { + var srcEl = document.getElementById("calendar"); + var parent = srcEl.parentNode; + var container = document.createElement("div"); + container.style.backgroundColor = "#FFFFFF"; + container.style.width = "3840px"; + document.body.appendChild(container); + container.appendChild(srcEl); + + var pdf = new jsPDF('l', 'mm', [1485, 270]); + pdf.addHTML(container, function () { + pdf.save('daily-planning.pdf'); + parent.appendChild(srcEl); + document.body.removeChild(container); + }); + } + } + }; + + var default_properties = { schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives', defaultView: 'agendaDay', eventDurationEditable: false, eventStartEditable: true, editable: true, selectable: true, - eventOverlap: function (stillEvent, movingEvent) { - if (stillEvent.rendering === "background") { - return true; - } - return false; - }, + droppable: true, weekends: false, + selectHelper: true, + groupByResource: true, + displayEventTime: true, scrollTime: '08:00', slotDuration: '00:30', snapDuration: '00:05', - displayEventTime: true, - resourceOrder: 'role', - resourceGroupField: 'role', - dragRevertDuration: 0, minTime: "08:00:00", maxTime: "19:00:00", - groupByResource: true, - height: "auto", - customButtons: { - datePickerButton: { - text: 'select', - click: function () { - var $btnCustom = $('.fc-datePickerButton-button'); - if ($(".calendar-datepicker").length > 0) { - $(".calendar-datepicker").remove(); - } - else { - $btnCustom.after('<div class="calendar-datepicker"/>'); - $(".calendar-datepicker").datepicker().on('changeDate', function (ev) { - $('#calendar').fullCalendar('gotoDate', ev.date); - $(".calendar-datepicker").remove(); - }); - } - } - }, - save: { - text: 'Save', - click: function () { - calendarEvents = $('#calendar').fullCalendar('clientEvents'); - eventsToPersist = []; - var saveButton = $(".fc-save-button"); - var currentBorder = saveButton.css('border-color'); - $.each(calendarEvents, function (i, calendar_event) { - if (calendar_event.rendering !== "background") { - eventsToPersist.push({ - 'link_id': calendar_event.link_id, - 'appointment_id': calendar_event.appointment_id, - 'link_who': parseInt(calendar_event.resourceId), - 'start': calendar_event.start.format() - }); - if (calendar_event.link_id !== undefined) { - var index = eventsCleared.indexOf(calendar_event.link_id); - if (index > -1) { - eventsCleared.splice(index, 1); - } - } else { - var index = appointmentsCleared.indexOf(calendar_event.appointment_id); - if (index > -1) { - appointmentsCleared.splice(index, 1); - } - } - } - }); - $.post({ - url: events_url, - data: { - events_to_persist: JSON.stringify(eventsToPersist), - events_to_clear: JSON.stringify(eventsCleared), - appointments_to_clear: JSON.stringify(appointmentsCleared) - }, - dataType: "json" - }).done(function (data) { - - saveButton.css('border-color', 'green'); - setTimeout(function () { - saveButton.css('border-color', currentBorder); - }, 200); - }).error(function (data) { - - console.log(data); - saveButton.css('border-color', 'red'); - showErrorInfo("There was an unexpected problem with saving data. " + - "Please contact administrators."); - setTimeout(function () { - saveButton.delay(200).css('border-color', currentBorder); - }, 200); - }); - } - }, - clear: { - text: 'Clear', - click: function () { - calendarEvents = $('#calendar').fullCalendar('clientEvents'); - $.each(calendarEvents, function (i, calendar_event) { - remove_event(calendar_event); - }); - } - }, - toPdf: { - text: 'PDF', - click: function () { - var srcEl = document.getElementById("calendar"); - var parent = srcEl.parentNode; - var container = document.createElement("div"); - container.style.backgroundColor = "#FFFFFF"; - container.style.width = "3840px"; - document.body.appendChild(container); - container.appendChild(srcEl); - - var pdf = new jsPDF('l', 'mm', [1485, 270]); - pdf.addHTML(container, function () { - pdf.save('daily-planning.pdf'); - parent.appendChild(srcEl); - document.body.removeChild(container); - }); - } - } - - }, - viewRender: function (view, element) { - var date = view.start.format('YYYY-MM-DD'); - $('#calendar').fullCalendar('removeEvents'); - get_subjects_events(date); - }, businessHours: { start: '08:00', end: '19:00' }, + dragRevertDuration: 0, + height: "auto", + customButtons: customButtons, header: { left: 'prev,next today', center: 'title, datePickerButton', right: 'save, clear, toPdf' }, - droppable: true, + // VIEW + viewRender: function (view, element) { + var date = view.start.format('YYYY-MM-DD'); + $(calendar_selector).fullCalendar('removeEvents'); + get_subjects_events(date); + }, + // RESOURCES + resourceOrder: 'role', + resourceGroupField: 'role', resourceAreaWidth: '15%', resourceLabelText: 'Workers', refetchResourcesOnNavigate: true, @@ -433,7 +431,7 @@ $(document).ready(function () { }, resources: function(callback){ setTimeout(function(){ - var view = $('#calendar').fullCalendar('getView'); + var view = $(calendar_selector).fullCalendar('getView'); $.ajax({ url: resources_url, type: 'GET', @@ -443,13 +441,14 @@ $(document).ready(function () { } }).then(function(resources){ //Filter out roles - var checked_roles = $('.role_list_item > input:checked').map( (i,e) => e.value).toArray(); - resources = resources.filter(resource => checked_roles.includes(resource.role)); - callback(resources) + if($('.role_list_item > input').length > 0){ + var checked_roles = $('.role_list_item > input:checked').map( (i,e) => e.value).toArray(); + resources = resources.filter(resource => checked_roles.includes(resource.role)); + } + callback(resources); }); }, 0); }, - events: [], eventRender: function (event, element) { if (event.rendering !== 'background') { var content = @@ -469,6 +468,13 @@ $(document).ready(function () { } else { } }, + // EVENTS + eventOverlap: function (stillEvent, movingEvent) { + if (stillEvent.rendering === "background") { + return true; + } + return false; + }, selectAllow: function (selectInfo) { return false; }, @@ -483,7 +489,6 @@ $(document).ready(function () { eventDragStart: function (event, jsEvent, view) { $('.popover').popover('hide'); }, - selectHelper: true, drop: function (date, jsEvent, ui, resourceId) { $(this).remove(); }, @@ -494,9 +499,20 @@ $(document).ready(function () { }; setTimeout(function() {resizeCalendarColumns()}, 100); } - }); -}) -; + }; + + // REPLACE DEFAULT PROPERTIES + if(replace_all){ + default_properties = calendar_dict_props; + }else{ + for (var key in calendar_dict_props) { + default_properties[key] = calendar_dict_props[key]; + } + } + + $(calendar_selector).fullCalendar(default_properties); + +} //RESIZE COLUMNS AND ENABLE HORIZONTAL SCROLL function resizeCalendarColumns(){ diff --git a/smash/web/static/js/smash.js b/smash/web/static/js/smash.js index 43ceca22c8a3da72cad3f33a0b61401ad1afc16d..fe4896e034810ee409dc35bc15e58593f15d7f5a 100644 --- a/smash/web/static/js/smash.js +++ b/smash/web/static/js/smash.js @@ -185,27 +185,55 @@ function create_visit_row(visit) { var text = "---"; if (visit !== undefined && visit !== null) { if (visit.status === "DONE") { - color = "green"; - text = "OK"; + color = "#6bff5a"; + text = `<span title="Visit is finished, all appointments done.">OK</span>`; + } else if (visit.status === "MISSED") { color = "pink"; - text = "MISSED"; + text = `<span title="Visit is finished, some appointments were not carried out.">MISSED</span>`; + } else if (visit.status === "UPCOMING") { color = "#00ffff"; - text = "UPCOMING"; + text = `<span title="Visit has not started yet.">UPCOMING</span>`; + } else if (visit.status === "EXCEEDED") { color = "orange"; - text = "EXCEEDED"; + text = `<span title="Visit is over and no appointments were set.">EXCEEDED</span>`; + } else if (visit.status === "SHOULD_BE_IN_PROGRESS") { color = "orange"; - text = "IN PROGRESS (NO APPOINTMENTS)"; + text = `<span title="Visit has started but no appointments have been set yet.">IN PROGRESS (NO APPOINTMENTS)</span>`; + } else if (visit.status === "IN_PROGRESS") { color = "lightgreen"; - text = "IN PROGRESS"; + text = `<span title="Appointments are taking place.">IN PROGRESS</span>`; + } - text += " <br/>" + visit.datetime_start + " - " + visit.datetime_end; + + var start_date = moment(visit.datetime_start); + var end_date = moment(visit.datetime_end); + + text += ` <br/> + <span data-html="true" title="From: ${start_date.format('ddd Do MMMM YYYY')} </br> To: ${end_date.format('ddd Do MMMM YYYY')}"> + From: ${start_date.format('D MMM. YYYY')} + </span> + <br/> + <span data-html="true" title="From: ${start_date.format('ddd Do MMMM YYYY')} </br> To: ${end_date.format('ddd Do MMMM YYYY')}"> + To: ${end_date.format('D MMM. YYYY')} + </span>` + + text += `<br/><span data-html="true" title="Visit details<br/>Appointment Types:<br/><div class='appointment_type_list'>${visit.appointment_types.join('<br/>')}</div>"> + <a href="${visit.edit_visit_url}"><i class="fa fa-list" aria-hidden="true"></i></a> + </span>`; + + if(!visit.is_finished){ + text += `<span title="Add new appointment to visit"><a href="${visit.add_appointment_url}"><i class="fa fa-plus-square-o" aria-hidden="true"></i></a></span>`; + }else{ + text += `<span title="Visit is marked as finished" ><i class="fa fa-check-circle" aria-hidden="true"></i></span>`; + } + } - return "<div style='background-color:" + color + "';width:100%;height:100%>" + text + "</div>"; + return "<div class='visit_row' style='background-color:" + color + "';width:100%;height:100%>" + text + "</div>"; } function createVisibilityCheckboxes(checkboxesElement, columns) { diff --git a/smash/web/static/js/visit.js b/smash/web/static/js/visit.js index a2636ed219748484b648296a736608d14732589c..1e5aa2208b0177fad7bd72613cf637f7681c6f3e 100644 --- a/smash/web/static/js/visit.js +++ b/smash/web/static/js/visit.js @@ -1,10 +1,12 @@ -function visit_dates_behaviour(startDateInput, endDateInput) { +function visit_dates_behaviour(startDateInput, endDateInput, default_visit_duration) { $(startDateInput).change(function () { var object = $(this); try { var date = new Date(object.val()); - date.setMonth(date.getMonth() + 3); - $(endDateInput).val(date.toISOString().substring(0, 10)); + date.setMonth(date.getMonth() + default_visit_duration); + if($(endDateInput).val() == ""){ + $(endDateInput).val(date.toISOString().substring(0, 10)); + } } catch (err) { //there was a problematic date to process } diff --git a/smash/web/templates/_base.html b/smash/web/templates/_base.html index 896dab32008ca3bdec67f7d35c0a0c6e4512a3d8..5d5a2e652d92d6e729e7709e46628b994c77f612 100644 --- a/smash/web/templates/_base.html +++ b/smash/web/templates/_base.html @@ -194,14 +194,21 @@ desired effect <!--<div class="pull-left"> <a href="#" class="btn btn-default btn-flat"><i class="fa fa-user"></i> Profile</a> </div>--> - <div class="pull-right"> - <a href="{% url 'logout' %}" class="btn btn-default btn-flat"><i - class="fa fa-sign-out"></i> Sign out</a> - </div> <div class="pull-left"> <a href="{% url 'two_factor:profile' %}" class="btn btn-default btn-flat"><i class="fa fa-lock"></i> Security</a> </div> + + <div style="display: inline-block;"> + <a href="{% url 'change_password' %}" class="btn btn-default btn-flat"> + <i class="fa fa-key" aria-hidden="true"></i> Change Password</a> + </div> + + <div class="pull-right"> + <a href="{% url 'logout' %}" class="btn btn-default btn-flat"><i + class="fa fa-sign-out"></i> Sign out</a> + </div> + </li> </ul> </li> @@ -379,6 +386,10 @@ desired effect var activate = function (page_to_activate) { var $e = $(".sidebar-menu li[data-desc='" + page_to_activate + "']"); $e.addClass("active"); + if($($e).parents('li[data-desc]').length > 0){ //if there is a parent, it should also be active + $($e).parents('li[data-desc]').addClass("active"); + } + }; activate({% block ui_active_tab %}{% endblock ui_active_tab %}); diff --git a/smash/web/templates/appointments/add.html b/smash/web/templates/appointments/add.html index bf87695b3f1f00caf74b6db18777f2ec762445be..9fc04985e5e152a2daf9db4790479f9bff949f36 100644 --- a/smash/web/templates/appointments/add.html +++ b/smash/web/templates/appointments/add.html @@ -4,12 +4,16 @@ {% block styles %} {{ block.super }} + <!-- DataTables --> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> <!-- fullCalendar 2.2.5--> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.css' %}"> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.print.css' %}" media="print"> + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar_custom.print.css' %}" media="print" /> + <link rel="stylesheet" href="{% static 'fullcalendar-scheduler/scheduler.min.css' %}"> + <link rel="stylesheet" href="{% static 'css/daily_planning.css' %}"> {% include "includes/datetimepicker.css.html" %} <link rel="stylesheet" href="{% static 'css/appointment.css' %}"> @@ -18,6 +22,17 @@ text-align: center !important; margin: 0; } + .tooltip_image{ + width: 20px !important; + margin: 5px; + } + .subject_title{ + padding: 0 !important; + } + .subject_title + .tooltip > .tooltip-inner, .column_title + .tooltip > .tooltip-inner { + background-color: #fafafa; + border: solid 1px #ccc; + } </style> {% endblock styles %} @@ -47,49 +62,61 @@ New appointment for visit from {{visit_start}} to {{visit_end}} <form method="post" action="" class="form-horizontal"> {% csrf_token %} - <div class="box-body"> - <div class="col-sm-6"> - {% for field in form %} - <div class="form-group {% if field.errors %}has-error{% endif %} {% if field|is_checkbox %}multi-checkboxes{% endif %}"> - <label class="col-sm-4 control-label"> - {{ field.label }} - </label> - - <div class="col-sm-8"> - {{ field|add_class:'form-control' }} + <div class="row"> + <div class="box-body"> + <div class="col-md-6"> + {% for field in form %} + <div class="form-group {% if field.errors %}has-error{% endif %} {% if field|is_checkbox %}multi-checkboxes{% endif %}"> + <label class="col-sm-4 control-label"> + {{ field.label }} + </label> + + <div class="col-sm-8"> + {{ field|add_class:'form-control' }} + </div> + + {% if field.errors %} + <span class="help-block"> + {{ field.errors }} + </span> + {% endif %} + </div> + {% endfor %} + </div> + <div class="col-md-6"> + <div class="box box-primary"> + <div class="box-body no-padding"> + <div id="side_calendar"></div> </div> - - {% if field.errors %} - <span class="help-block"> - {{ field.errors }} - </span> - {% endif %} - </div> - {% endfor %} - </div> - <div class="col-md-6"> - <div class="box box-primary"> - <div class="box-body no-padding"> - <div id="calendar"></div> </div> </div> - </div> - </div><!-- /.box-body --> - - - <div class="box-footer"> - <div class="col-sm-6"> - <button type="submit" class="btn btn-block btn-success">Add</button> - </div> - <div class="col-sm-6"> - <a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default">Cancel</a> - </div> - </div><!-- /.box-footer --> + </div><!-- /.box-body --> + </div> + <div class="row"> + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-success">Add</button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </div> </form> </div> + <div class="row"> + <div class="col-md-12"> + <div class="box box-primary"> + <div class="box-body no-padding"> + <div id="calendar"></div> + </div> + </div> + </div> + </div> + {% endblock %} @@ -101,8 +128,9 @@ New appointment for visit from {{visit_start}} to {{visit_end}} <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/moment.js/moment.min.js' %}"></script> - <script src="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.js' %}"></script> <script src="{% static 'js/appointment.js' %}"></script> + <script src="{% static 'fullcalendar-scheduler/lib/fullcalendar.min.js' %}"></script> + <script src="{% static 'fullcalendar-scheduler/scheduler.min.js' %}"></script> <script> $(function () { $('#table').DataTable({ @@ -113,14 +141,16 @@ New appointment for visit from {{visit_start}} to {{visit_end}} "info": true, "autoWidth": false }); - $('#calendar').fullCalendar({ - defaultDate: moment('{{visit_start}}'), + //SIDE CALENDAR + addDailyPlanningCalendar('#side_calendar', true, { + schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives', + defaultDate: moment.max(moment('{{visit_start}}'), moment()), + editable: false, header: { left: 'prev,next today', center: 'title', right: 'month,agendaWeek' }, - editable: false, dayClick: function (date, jsEvent, view) { var dateString = date.format(); if (dateString.indexOf("T") >= 0) { @@ -129,6 +159,7 @@ New appointment for visit from {{visit_start}} to {{visit_end}} dateString = dateString + " 09:00"; } document.getElementById("id_datetime_when").value = dateString; + $('#id_datetime_when').change(); getWorkerAvailability(); }, eventClick: function (calEvent, jsEvent, view) { @@ -214,7 +245,35 @@ New appointment for visit from {{visit_start}} to {{visit_end}} } $('select.search_worker_availability, input[name="datetime_when"], input[name="length"]').on("change", getWorkerAvailability); + + $("#id_datetime_when").on("change paste keyup", function() { + var date = $("#id_datetime_when").val(); + date = moment(date); + $('#calendar').fullCalendar('gotoDate', date); + }); + + var resources_url = '{% url 'web.api.workers.daily_planning' %}'; + var events_url = '{% url 'web.api.events_persist' %}'; + + $(document).ready(function () { + addDailyPlanningCalendar('#calendar', false, { + eventDurationEditable: false, + eventStartEditable: false, + editable: false, + selectable: false, + droppable: false, + customButtons: {}, + header: { + left: '', + center: 'title', + right: '' + } + }); + }); + </script> {% include "includes/datetimepicker.js.html" %} + <script src="{% static 'js/daily_planning.js' %}"></script> + {% endblock scripts %} diff --git a/smash/web/templates/configuration/breadcrumb.html b/smash/web/templates/configuration/breadcrumb.html index 236d1bc335add0ec4427809a9c3c7e94a6490f26..737ff03042e6505dee855e4cd14da66fc9a5937e 100644 --- a/smash/web/templates/configuration/breadcrumb.html +++ b/smash/web/templates/configuration/breadcrumb.html @@ -1,4 +1,5 @@ <li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> +<li>Configuration</li> <li class="active"> - <a href="{% url 'web.views.configuration' %}">Configuration</a> + <a href="{% url 'web.views.configuration' %}">General</a> </li> diff --git a/smash/web/templates/configuration/index.html b/smash/web/templates/configuration/index.html index 7330cbc831b41c140a70a67eeeeb3aa1354305fc..d5580458239aeb03c3cd24323d5be81f70cfc513 100644 --- a/smash/web/templates/configuration/index.html +++ b/smash/web/templates/configuration/index.html @@ -9,7 +9,7 @@ {% endblock styles %} -{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %} +{% block ui_active_tab %}'general_conf'{% endblock ui_active_tab %} {% block page_header %}Configuration{% endblock page_header %} {% block page_description %}{% endblock page_description %} diff --git a/smash/web/templates/daily_planning.html b/smash/web/templates/daily_planning.html index 63b552701589c09f7ce5b04d23c9e827277bc131..4d6cc2058df16128406951a76d9223d55730fbeb 100644 --- a/smash/web/templates/daily_planning.html +++ b/smash/web/templates/daily_planning.html @@ -85,6 +85,10 @@ $('#calendar').fullCalendar('refetchResources'); } + $(document).ready(function () { + addDailyPlanningCalendar('#calendar', false, {}); + }); + </script> {% include "includes/datepicker.js.html" %} <script src="{% static 'js/daily_planning.js' %}"></script> diff --git a/smash/web/templates/doctors/breadcrumb.html b/smash/web/templates/doctors/breadcrumb.html index 6d111dd545adc0d422fe4dfae996671af3c8f657..391f87d887db27dadfd5b2a7f390967d920769fd 100644 --- a/smash/web/templates/doctors/breadcrumb.html +++ b/smash/web/templates/doctors/breadcrumb.html @@ -1,2 +1,7 @@ <li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> +{% if worker_type == 'HEALTH_PARTNER' %} +<li>Configuration</li> +{% elif worker_type == 'VOUCHER_PARTNER' %} +<li>Configuration</li> +{% endif %} <li class="active"><a href="{% url 'web.views.workers' %}">Workers</a></li> \ No newline at end of file diff --git a/smash/web/templates/doctors/change_password.html b/smash/web/templates/doctors/change_password.html new file mode 100644 index 0000000000000000000000000000000000000000..17ee498118c8860f6066cb80b3513694ccab0e8c --- /dev/null +++ b/smash/web/templates/doctors/change_password.html @@ -0,0 +1,51 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + <!-- DataTables --> + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> + <style type="text/css"> + .hidden_form_field{ + display: none; + } + form.password_change{ + display: grid; + max-width: 400px; + } + button[type=submit]{ + margin-top: 15px; + } + </style> +{% endblock styles %} + +{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} + +{% block title %}{{ block.super }} - Change password {% endblock %} + +{% block page_header %} Changing password for worker <b>{{ worker }}</b> with username: <b>{{ user }}</b> {% endblock page_header %} + +{% block breadcrumb %} + {% include "doctors/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + +<form class="password_change" method="post"> + {% csrf_token %} + {{ form }} + <button type="submit">Save changes</button> +</form> + + +{% endblock %} + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + +{% endblock scripts %} \ No newline at end of file diff --git a/smash/web/templates/doctors/edit.html b/smash/web/templates/doctors/edit.html index fb689494e717f705c657633b0dc42508d0968e22..40217781f9abb8c425bec1583485298060d82c45 100644 --- a/smash/web/templates/doctors/edit.html +++ b/smash/web/templates/doctors/edit.html @@ -37,6 +37,9 @@ <div class="col-md-6 form-group {% if field.errors %}has-error{% endif %} {{ field.field.widget.attrs.class }}"> <label for="{# TODO #}" class="col-sm-4 control-label"> {{ field.label }} + {% if field.help_text %} + <i class="fa fa-info-circle" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="{{field.help_text}}"></i> + {% endif %} </label> <div class="col-sm-8"> diff --git a/smash/web/templates/doctors/index.html b/smash/web/templates/doctors/index.html index 1accfd94d238279684ff6d4fe11d6085b05976b8..e1b0fef9d130e9837600cea02f05ca0e849de70d 100644 --- a/smash/web/templates/doctors/index.html +++ b/smash/web/templates/doctors/index.html @@ -5,10 +5,34 @@ {{ block.super }} <!-- DataTables --> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> + <style type="text/css"> + .no_leave{ + height: 100%; + line-height: 2.5; + text-align: center; + background-color: #00a65b; + } + .on_leave{ + height: 100%; + line-height: 2.5; + text-align: center; + background-color: #dd4b39; + } + </style> {% endblock styles %} -{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} +{% block ui_active_tab %} +{% if worker_type == 'STAFF' %} +'workers' +{% elif worker_type == 'HEALTH_PARTNER' %} +'health_partners' +{% elif worker_type == 'VOUCHER_PARTNER' %} +'voucher_partners' +{% endif %} +{% endblock ui_active_tab %} + {% block page_header %} + {% if worker_type == 'STAFF' %} Workers {% elif worker_type == 'HEALTH_PARTNER' %} @@ -16,6 +40,7 @@ {% elif worker_type == 'VOUCHER_PARTNER' %} Voucher Partners {% endif %} + {% endblock page_header %} {% block breadcrumb %} {% include "doctors/breadcrumb.html" %} @@ -53,7 +78,7 @@ <th>Languages</th> <th>Details</th> {% if worker_type == 'STAFF' %} - <th>On leave</th> + <th>At work</th> <th>Disabled</th> {% endif %} </tr> @@ -82,9 +107,9 @@ {% if worker_type == 'STAFF' %} <td> {% if worker.is_on_leave %} - <button type="button" class="btn btn-block btn-danger">YES</button> + <div title="Worker is on leave until: {{ worker.current_leave_details.datetime_end }}" class="on_leave">✘</div> {% else %} - <button type="button" class="btn btn-block btn-success">NO</button> + <div title="Worker is not on leave" class="no_leave">✔</div> {% endif %} </td> <td> @@ -120,5 +145,7 @@ "autoWidth": false }); }); + + $('.no_leave, .on_leave').tooltip(); </script> {% endblock scripts %} diff --git a/smash/web/templates/includes/visit_appointment_types_field.html b/smash/web/templates/includes/visit_appointment_types_field.html index 4e167755b38db5821992197a8d3edf9ddb12245c..8cd1998f280aaebad4286e617f260e0191f00dbd 100644 --- a/smash/web/templates/includes/visit_appointment_types_field.html +++ b/smash/web/templates/includes/visit_appointment_types_field.html @@ -13,7 +13,7 @@ background: orange; {% endif %}{% endif %}{% endfor %}{% endfor %} "></div> - <input {% if readonly %}disabled="disabled"{% endif %} + <input {% if field.field.widget.attrs.readonly %}disabled="disabled"{% endif %} {% for option in field.value %}{% if option == pk|slugify or option == pk %}checked="checked" {% endif %}{% endfor %} type="checkbox" id="id_{{ field.name }}_{{ forloop.counter0 }}" diff --git a/smash/web/templates/languages/breadcrumb.html b/smash/web/templates/languages/breadcrumb.html index b3194bfb0a32794c726a75682425d7ea4b17f30d..6e78554facad42d8816fb4f9dd84e0a8f5dd3535 100644 --- a/smash/web/templates/languages/breadcrumb.html +++ b/smash/web/templates/languages/breadcrumb.html @@ -1,2 +1,5 @@ <li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> -<li class="active"><a href="{% url 'web.views.languages' %}">Languages</a></li> \ No newline at end of file +<li>Configuration</li> +<li class="active"> + <a href="{% url 'web.views.languages' %}">Languages</a> +</li> \ No newline at end of file diff --git a/smash/web/templates/languages/list.html b/smash/web/templates/languages/list.html index eeb9eb68a3fff742857578282926129f210be213..33a5e5178c7c4b9355776bb5f588e0d2b76c64a3 100644 --- a/smash/web/templates/languages/list.html +++ b/smash/web/templates/languages/list.html @@ -7,7 +7,7 @@ <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> {% endblock styles %} -{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %} +{% block ui_active_tab %}'languages'{% endblock ui_active_tab %} {% block page_header %}Languages{% endblock page_header %} {% block page_description %}{% endblock page_description %} diff --git a/smash/web/templates/login.html b/smash/web/templates/login.html index e3ba68154ec303856c01c9e10ccad9f7671528b6..9de902ceacbfe6584ab6624c551ddba2e13d30f2 100644 --- a/smash/web/templates/login.html +++ b/smash/web/templates/login.html @@ -1,6 +1,9 @@ {% load static %}<!DOCTYPE html> <html> <head> + {% if user.is_authenticated %} + <meta http-equiv="REFRESH" content="0;url={% url 'web.views.index' %}"> + {% endif %} <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Scheduling System | Log in</title> diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index f4b3c8575046b51a695816f564e40c7e02272e37..89c8b23ba6c1f8bbf72801253c61a9fab6d1c663 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -23,12 +23,14 @@ </a> </li> + {% if "change_worker" in permissions %} <li data-desc="workers"> <a href="{% url 'web.views.workers' %}"> <i class="fa fa-user-md"></i> - <span>Workers</span> + <span>Worker</span> </a> </li> + {% endif %} <li data-desc="equipment_and_rooms" class="treeview"> <a href="{% url 'web.views.equipment_and_rooms' %}"> @@ -66,7 +68,7 @@ </a> </li> - {% if study.has_vouchers %} + {% if study.has_vouchers and "change_voucher" in permissions%} <li data-desc="vouchers"> <a href="{% url 'web.views.vouchers' %}"> <i class="fa fa-user-md"></i> @@ -75,6 +77,8 @@ </li> {% endif %} + {% if conf_perms %} + <li data-desc="configuration" class="treeview"> <a href="#"> <i class="fa fa-wrench"></i> <span>Configuration</span> @@ -83,17 +87,32 @@ </span> </a> <ul class="treeview-menu"> + {% if "change_configurationitem" in permissions %} <li><a href="{% url 'web.views.configuration' %}">General</a></li> + {% endif %} + + {% if "change_language" in permissions %} <li><a href="{% url 'web.views.languages' %}">Languages</a></li> - {% if study.has_voucher_types %} + {% endif %} + + {% if study.has_voucher_types and "change_vouchertype" in permissions %} <li><a href="{% url 'web.views.voucher_types' %}">Voucher types</a></li> {% endif %} - {% if study.has_vouchers %} + + {% if study.has_vouchers and "change_worker" in permissions %} <li><a href="{% url 'web.views.workers' 'VOUCHER_PARTNER' %}">Voucher partners</a></li> {% endif %} + + {% if "change_worker" in permissions %} <li><a href="{% url 'web.views.workers' 'HEALTH_PARTNER' %}">Health partners</a></li> + {% endif %} + + {% if "change_study" in permissions %} <li><a href="{% url 'web.views.edit_study' study_id %}">Study</a></li> + {% endif %} </ul> </li> + {% endif %} + </ul> diff --git a/smash/web/templates/study/breadcrumb.html b/smash/web/templates/study/breadcrumb.html new file mode 100644 index 0000000000000000000000000000000000000000..f6052818f23962928e0f9d250f8b163cbb5c7747 --- /dev/null +++ b/smash/web/templates/study/breadcrumb.html @@ -0,0 +1,3 @@ +<li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> +<li>Configuration</li> +<li class="active"><a href="{% url 'web.views.edit_study' study_id %}">Study</a></li> \ No newline at end of file diff --git a/smash/web/templates/study/edit.html b/smash/web/templates/study/edit.html index e1e8d594d914cae156ec0bbac6bb0b134b9e488b..760f930b8d2338ac28c97dc5a9a3aa825bdee8e2 100644 --- a/smash/web/templates/study/edit.html +++ b/smash/web/templates/study/edit.html @@ -16,14 +16,14 @@ {% include "includes/datetimepicker.css.html" %} {% endblock styles %} -{% block ui_active_tab %}'subjects'{% endblock ui_active_tab %} +{% block ui_active_tab %}'study_conf'{% endblock ui_active_tab %} {% block page_header %}Edit subject{% endblock page_header %} {% block page_description %}{% endblock page_description %} {% block title %}{{ block.super }} - Edit subject information{% endblock %} {% block breadcrumb %} - {% include "subjects/breadcrumb.html" %} + {% include "study/breadcrumb.html" %} {% endblock breadcrumb %} {% block maincontent %} diff --git a/smash/web/templates/subjects/index.html b/smash/web/templates/subjects/index.html index d147846f452cff0fa9ecdb3193af5246672de120..4b8dd79da85b5efbccc6cb212d687e2effd5c2ed 100644 --- a/smash/web/templates/subjects/index.html +++ b/smash/web/templates/subjects/index.html @@ -3,6 +3,7 @@ {% block styles %} {{ block.super }} + <script src="{% static 'AdminLTE/plugins/moment.js/moment.min.js' %}"></script> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> <style type="text/css"> .box-body { @@ -12,12 +13,29 @@ font-weight: bolder; border-bottom: black 1px solid; } + .dataTables_length{ display: inline-block; } .dt-buttons{ margin-left: 10px; } + .visit_row{ + font-size: 10pt; + max-width: 22ch; + min-width: 18ch; + text-align: center; + } + .visit_row > span{ + padding-right: 2px; + padding-left: 2px; + } + .visit_row > span > a{ + color: inherit; + } + .appointment_type_list{ + margin-top: 10px; + text-align: left; </style> {% endblock styles %} @@ -88,6 +106,11 @@ }) }); + $('body').tooltip({ + selector: '.visit_row > span[title]', + trigger: 'hover' + }); + </script> {% endblock scripts %} diff --git a/smash/web/templates/visits/add.html b/smash/web/templates/visits/add.html index 749641be57b7d9c1e4160a5d7457fff0cbfa5fed..4c93ee497b56c5d68886deb070115662d1fa3e05 100644 --- a/smash/web/templates/visits/add.html +++ b/smash/web/templates/visits/add.html @@ -70,7 +70,8 @@ <script src="{% static 'js/visit.js' %}"></script> <script> - visit_dates_behaviour($("[name='datetime_begin']"),$("[name='datetime_end']")); + var default_visit_duration_in_months = parseInt("{{default_visit_duration}}"); + visit_dates_behaviour($("[name='datetime_begin']"), $("[name='datetime_end']"), default_visit_duration_in_months); </script> {% include "includes/datepicker.js.html" %} diff --git a/smash/web/templates/visits/details.html b/smash/web/templates/visits/details.html index 62069efad065578c2615da6a13a554e261b11629..a85ce75d1f33ac0ce2284b723f1fca38ef46ea1c 100644 --- a/smash/web/templates/visits/details.html +++ b/smash/web/templates/visits/details.html @@ -91,10 +91,17 @@ </div> <div> + {%if visFinished%} + <a href="{% url 'web.views.appointment_add' vid %}" class="btn btn-app" disabled> + <i class="fa fa-plus"></i> + Add new appointment + </a> + {% else %} <a href="{% url 'web.views.appointment_add' vid %}" class="btn btn-app"> <i class="fa fa-plus"></i> Add new appointment </a> + {% endif %} </div> @@ -221,7 +228,8 @@ <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> <script src="{% static 'js/visit.js' %}"></script> <script> - visit_dates_behaviour($("[name='datetime_begin']"), $("[name='datetime_end']")); + var default_visit_duration_in_months = parseInt("{{default_visit_duration}}"); + visit_dates_behaviour($("[name='datetime_begin']"), $("[name='datetime_end']"), default_visit_duration_in_months); </script> {% include "includes/datepicker.js.html" %} diff --git a/smash/web/templates/voucher_types/breadcrumb.html b/smash/web/templates/voucher_types/breadcrumb.html index 844971e607ceace28009bea2b53bf6ccd423ba0d..d3fe1508ae40cd59514f2c828129472bb89bd6b1 100644 --- a/smash/web/templates/voucher_types/breadcrumb.html +++ b/smash/web/templates/voucher_types/breadcrumb.html @@ -1,2 +1,3 @@ <li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> +<li>Configuration</li> <li class="active"><a href="{% url 'web.views.voucher_types' %}">Voucher types</a></li> \ No newline at end of file diff --git a/smash/web/templates/voucher_types/list.html b/smash/web/templates/voucher_types/list.html index dec5cde7cb9c8db00538232581c1ebc6d11bb42a..22ae47336625cf36d56ebf8d41793e45e0956cb2 100644 --- a/smash/web/templates/voucher_types/list.html +++ b/smash/web/templates/voucher_types/list.html @@ -7,7 +7,7 @@ <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> {% endblock styles %} -{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %} +{% block ui_active_tab %}'voucher_types'{% endblock ui_active_tab %} {% block page_header %}Voucher types{% endblock page_header %} {% block page_description %}{% endblock page_description %} diff --git a/smash/web/tests/__init__.py b/smash/web/tests/__init__.py index 692232677b9701a19afaa9b63a85628248f09e5f..1b351ebb9b61696606c63b71921ce5b46e6600fe 100644 --- a/smash/web/tests/__init__.py +++ b/smash/web/tests/__init__.py @@ -4,8 +4,10 @@ from django.conf import settings from django.contrib.auth.models import User from django.test import Client from django.test import TestCase +from web.models import Worker +from web.decorators import PermissionDecorator -from functions import create_worker +from functions import create_worker, create_user, add_permissions_to_worker settings.MEDIA_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data') @@ -14,6 +16,15 @@ logger = logging.getLogger(__name__) class LoggedInTestCase(TestCase): def setUp(self): + self.password = 'abcd1234' + #superuser + self.super_worker = create_worker(user=User.objects.create_superuser(username='super', password=self.password, email='a@mail.com')) + #admin + self.admin_worker = Worker.get_by_user(create_user(username='admin', password=self.password)) + add_permissions_to_worker(self.admin_worker, PermissionDecorator.codenames) + #staff + self.staff_worker = Worker.get_by_user(create_user(username='staff', password=self.password)) + self.client = Client() username = 'piotr' password = 'top_secret' @@ -21,6 +32,18 @@ class LoggedInTestCase(TestCase): username=username, email='jacob@bla', password=password) self.client.login(username=username, password=password) + def login_as_staff(self): + self.client.logout() + self.client.login(username='staff', password=self.password) + + def login_as_admin(self): + self.client.logout() + self.client.login(username='admin', password=self.password) + + def login_as_super(self): + self.client.logout() + self.client.login(username='super', password=self.password) + class LoggedInWithWorkerTestCase(LoggedInTestCase): def setUp(self): diff --git a/smash/web/tests/forms/test_study_forms.py b/smash/web/tests/forms/test_study_forms.py index 6893bce69694866e8da3838acf419365776663a8..0fe2bd2cd5f0b9fce56a6f11feef5e9bb471fd49 100644 --- a/smash/web/tests/forms/test_study_forms.py +++ b/smash/web/tests/forms/test_study_forms.py @@ -18,16 +18,15 @@ class StudyFormTests(TestCase): 'nd_number_study_subject_regex').get_default() form.cleaned_data = { 'nd_number_study_subject_regex': nd_number_study_subject_regex_default} - self.assertTrue(form.clean_nd_number_study_subject_regex() - == nd_number_study_subject_regex_default) + + self.assertTrue(form.clean()['nd_number_study_subject_regex'] == nd_number_study_subject_regex_default) # test wrong regex form = StudyEditForm() form.instance = get_test_study() nd_number_study_subject_regex_default = r'^nd\d{5}$' form.cleaned_data = { 'nd_number_study_subject_regex': nd_number_study_subject_regex_default} - self.assertRaises( - ValidationError, form.clean_nd_number_study_subject_regex) + self.assertFalse(form.is_valid()) def test_study_other_regex(self): StudySubject.objects.all().delete() @@ -39,5 +38,5 @@ class StudyFormTests(TestCase): nd_number_study_subject_regex_default = r'^nd\d{5}$' form.cleaned_data = { 'nd_number_study_subject_regex': nd_number_study_subject_regex_default} - self.assertTrue(form.clean_nd_number_study_subject_regex() + self.assertTrue(form.clean()['nd_number_study_subject_regex'] == nd_number_study_subject_regex_default) diff --git a/smash/web/tests/forms/test_voucher_forms.py b/smash/web/tests/forms/test_voucher_forms.py index 17a25f96a4699ef3cc7173a0633fd1854f277e8f..42a800080be3ad89dd84728214e86597b70367ad 100644 --- a/smash/web/tests/forms/test_voucher_forms.py +++ b/smash/web/tests/forms/test_voucher_forms.py @@ -20,6 +20,7 @@ class VoucherFormTests(LoggedInWithWorkerTestCase): self.voucher_partner = create_voucher_partner() def test_create_voucher(self): + self.login_as_admin() voucher_type = create_voucher_type() study_subject = create_study_subject() study_subject.voucher_types.add(voucher_type) @@ -43,6 +44,7 @@ class VoucherFormTests(LoggedInWithWorkerTestCase): self.assertEqual(2, Voucher.objects.all().count()) def test_invalid_usage_partner(self): + self.login_as_admin() study_subject = create_study_subject() voucher = create_voucher(study_subject) voucher.status = VOUCHER_STATUS_USED diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py index e900d8c0a2ebca721322718f635e723902353427..cbe911f8f932e81aeed5924dd7377cfd9d7bbf99 100644 --- a/smash/web/tests/functions.py +++ b/smash/web/tests/functions.py @@ -13,6 +13,7 @@ from web.models.constants import REDCAP_TOKEN_CONFIGURATION_TYPE, REDCAP_BASE_UR from web.models.worker_study_role import ROLE_CHOICES_DOCTOR, WORKER_VOUCHER_PARTNER from web.redcap_connector import RedcapSubject from web.views.notifications import get_today_midnight_date +from django.contrib.auth.models import Permission logger = logging.getLogger(__name__) @@ -238,6 +239,11 @@ def create_user(username=None, password=None): create_worker(user) return user +def add_permissions_to_worker(worker, codenames): + roles = WorkerStudyRole.objects.filter(worker=worker, study_id=GLOBAL_STUDY_ID) + perms = Permission.objects.filter(codename__in=codenames).all() + roles[0].permissions.set(perms) + roles[0].save() def create_worker(user=None, with_test_location=False): worker = Worker.objects.create( diff --git a/smash/web/tests/models/test_visit.py b/smash/web/tests/models/test_visit.py index a247d83886c073d3d40d4318949b98817dc7924a..d9c7efb9c1c416f98e83d4fecac819d4433512e2 100644 --- a/smash/web/tests/models/test_visit.py +++ b/smash/web/tests/models/test_visit.py @@ -1,13 +1,103 @@ import datetime - +from dateutil.relativedelta import relativedelta from django.test import TestCase from web.models import Visit from web.models.constants import SUBJECT_TYPE_CHOICES_PATIENT from web.tests.functions import create_study_subject, create_visit +from web.utils import get_today_midnight_date +import logging +logger = logging.getLogger(__name__) class VisitModelTests(TestCase): + def test_so_called_no_concurrency(self): + subject = create_study_subject() + Visit.objects.filter(subject=subject).all().delete() + visit1 = create_visit(subject=subject) + visit1.datetime_end = get_today_midnight_date() + datetime.timedelta(days=1) + visit1.save() + self.assertEquals(1, visit1.visit_number) + visit2 = create_visit(subject=subject) + visit2.datetime_end = get_today_midnight_date() + datetime.timedelta(days=2) + visit2.save() + visit2.refresh_from_db() + self.assertEquals(2, visit2.visit_number) + + def test_socalled_concurrency(self): + subject = create_study_subject() + Visit.objects.filter(subject=subject).all().delete() + visit1 = create_visit(subject=subject) #post save will be raised + visit2 = create_visit(subject=subject) #post save will be raised + + visit1.datetime_end = get_today_midnight_date() + datetime.timedelta(days=1) + visit2.datetime_end = get_today_midnight_date() + datetime.timedelta(days=2) + + visit1.save() #post save will be raised + visit2.save() #post save will be raised + + visit1.refresh_from_db() + visit2.refresh_from_db() + self.assertEquals(1, visit1.visit_number) + self.assertEquals(2, visit2.visit_number) + + datetime_begin = get_today_midnight_date() - datetime.timedelta(days=60) + datetime_end = get_today_midnight_date() - datetime.timedelta(days=55) + visit3 = create_visit(subject=subject, datetime_begin=datetime_begin, datetime_end=datetime_end) #post save will be raised + visit1.refresh_from_db() + visit2.refresh_from_db() + visit3.refresh_from_db() + self.assertEquals(1, visit3.visit_number) + self.assertEquals(2, visit1.visit_number) + self.assertEquals(3, visit2.visit_number) + + def test_visit_numbers(self): + subject = create_study_subject() + Visit.objects.filter(subject=subject).all().delete() + visit1 = create_visit(subject=subject, + datetime_begin = get_today_midnight_date() - datetime.timedelta(days=15), + datetime_end = get_today_midnight_date() - datetime.timedelta(days=14)) #post save will be raised + visit2 = create_visit(subject=subject, + datetime_begin = get_today_midnight_date(), + datetime_end = get_today_midnight_date() + datetime.timedelta(days=2)) #post save will be raised + visit3 = create_visit(subject=subject, + datetime_begin = get_today_midnight_date() + datetime.timedelta(days=5), + datetime_end = get_today_midnight_date() + datetime.timedelta(days=10)) #post save will be raised + + # order should be [V1, V2, V3] + visit1.refresh_from_db() + visit2.refresh_from_db() + visit3.refresh_from_db() + self.assertEquals(1, visit1.visit_number) + self.assertEquals(2, visit2.visit_number) + self.assertEquals(3, visit3.visit_number) + + #NOW, move V3 between V1 and V2 + visit3.datetime_begin = get_today_midnight_date() - datetime.timedelta(days=11) + visit3.datetime_end = get_today_midnight_date() - datetime.timedelta(days=10) + visit3.save() #post save will be raised and V1, V2 and V3 should change their visits numbers + + #order now should be [V1, V3, V2] + visit1.refresh_from_db() + visit2.refresh_from_db() + visit3.refresh_from_db() + self.assertEquals(1, visit1.visit_number) + self.assertEquals(3, visit2.visit_number) #<= change + self.assertEquals(2, visit3.visit_number) #<= change + + #NOW, move V1 after V2 and V3 + visit1.datetime_begin = get_today_midnight_date() + datetime.timedelta(days=110) + visit1.datetime_end = get_today_midnight_date() + datetime.timedelta(days=111) + visit1.save() #post save will be raised and V1, V2 and V3 should change their visits numbers + + #order now should be [V3, V2, V1] + visit1.refresh_from_db() + visit2.refresh_from_db() + visit3.refresh_from_db() + self.assertEquals(3, visit1.visit_number) #<= change + self.assertEquals(2, visit2.visit_number) #<= change + self.assertEquals(1, visit3.visit_number) #<= change + def test_mark_as_finished(self): subject = create_study_subject() visit = create_visit(subject) @@ -47,7 +137,8 @@ class VisitModelTests(TestCase): visit.mark_as_finished() - follow_up_visit = Visit.objects.filter(subject=subject).filter(visit_number=2)[0] + visit_number=2 + follow_up_visit = Visit.objects.filter(subject=subject).filter(visit_number=visit_number)[0] follow_up_visit.datetime_begin = visit.datetime_begin + datetime.timedelta(days=133) follow_up_visit.datetime_end = visit.datetime_begin + datetime.timedelta(days=170) follow_up_visit.save() @@ -57,10 +148,16 @@ class VisitModelTests(TestCase): visit_count = Visit.objects.filter(subject=subject).count() self.assertEquals(3, visit_count) - new_follow_up = Visit.objects.filter(subject=subject).filter(visit_number=3)[0] + visit_number=3 + new_follow_up = Visit.objects.filter(subject=subject).filter(visit_number=visit_number)[0] # check if follow up date is based on the first visit date - self.assertTrue(visit.datetime_begin + datetime.timedelta(days=365 * 2 - 1) < new_follow_up.datetime_begin) + study = visit.subject.study + args = {study.default_delta_time_for_follow_up_units: study.default_delta_time_for_patient_follow_up} #patient + + time_to_next_visit = relativedelta(**args) * (visit_number - 1) #calculated from first visit + + self.assertTrue(visit.datetime_begin + time_to_next_visit - datetime.timedelta(days=1) < new_follow_up.datetime_begin) def test_visit_to_string(self): visit = create_visit(create_study_subject()) diff --git a/smash/web/tests/models/test_worker.py b/smash/web/tests/models/test_worker.py index 338ef668e0ca0b9befe465f28e17884ba7613f98..97c0ac5092bbbf483c14fb919fbe944eae5ac5ef 100644 --- a/smash/web/tests/models/test_worker.py +++ b/smash/web/tests/models/test_worker.py @@ -61,6 +61,16 @@ class WorkerModelTests(TestCase): self.assertTrue(worker.is_on_leave()) + def test_current_leave_details(self): + worker = create_worker() + self.assertEqual(worker.current_leave_details(), None) + h = Holiday(person=worker, + datetime_start=get_today_midnight_date() + datetime.timedelta(days=-2), + datetime_end=get_today_midnight_date() + datetime.timedelta(days=2)) + h.save() + + self.assertEqual(worker.current_leave_details(), h) + def test_get_by_user_for_anonymous(self): self.assertIsNone(Worker.get_by_user(AnonymousUser())) diff --git a/smash/web/tests/view/test_configuration.py b/smash/web/tests/view/test_configuration.py index 024f5e24d59c91245253108f4cab248f32929f45..49a32739bddd292bf5d99a65f2a01e98eca2f467 100644 --- a/smash/web/tests/view/test_configuration.py +++ b/smash/web/tests/view/test_configuration.py @@ -2,8 +2,17 @@ from django.urls import reverse from web.tests import LoggedInTestCase +import logging +logger = logging.getLogger(__name__) class ConfigurationViewTests(LoggedInTestCase): def test_visit_details_request(self): + self.login_as_admin() response = self.client.get(reverse('web.views.configuration')) + self.assertEqual(response.status_code, 200) + + def test_visit_details_request_without_permissions(self): + self.login_as_staff() + response = self.client.get(reverse('web.views.configuration')) + self.assertEqual(response.status_code, 302) diff --git a/smash/web/tests/view/test_study.py b/smash/web/tests/view/test_study.py index 93f9919b0e2378c168bd9c7eaf6e20e19bf2a7e3..6b7f18b6e90f2190f03ea9ef233a390807c668af 100644 --- a/smash/web/tests/view/test_study.py +++ b/smash/web/tests/view/test_study.py @@ -16,9 +16,15 @@ class SubjectsViewTests(LoggedInWithWorkerTestCase): self.study = get_test_study() def test_render_study_edit(self): + self.login_as_admin() response = self.client.get(reverse('web.views.edit_study', kwargs={'study_id': GLOBAL_STUDY_ID})) self.assertEqual(response.status_code, 200) + def test_render_study_edit_staff(self): + self.login_as_staff() + response = self.client.get(reverse('web.views.edit_study', kwargs={'study_id': GLOBAL_STUDY_ID})) + self.assertEqual(response.status_code, 302) + def test_save_study(self): form_data = self.create_edit_form_data_for_study() @@ -29,6 +35,7 @@ class SubjectsViewTests(LoggedInWithWorkerTestCase): self.assertFalse("edit" in response['Location']) def test_save_invalid_data(self): + self.login_as_admin() form_data = {} response = self.client.post( @@ -36,7 +43,17 @@ class SubjectsViewTests(LoggedInWithWorkerTestCase): self.assertEqual(response.status_code, 200) + def test_save_invalid_data_staff(self): + self.login_as_staff() + form_data = {} + + response = self.client.post( + reverse('web.views.edit_study', kwargs={'study_id': GLOBAL_STUDY_ID}), data=form_data) + + self.assertEqual(response.status_code, 302) + def test_save_study_without_changing_page(self): + self.login_as_admin() form_data = self.create_edit_form_data_for_study() form_data['_continue'] = True diff --git a/smash/web/tests/view/test_voucher.py b/smash/web/tests/view/test_voucher.py index 40237c10b79cdb19a4c10ecf4eee65606bf23d24..87390c8e8710a2727624cf4a1f368224617a2286 100644 --- a/smash/web/tests/view/test_voucher.py +++ b/smash/web/tests/view/test_voucher.py @@ -17,17 +17,33 @@ logger = logging.getLogger(__name__) class VoucherTypeViewTests(LoggedInTestCase): def test_render_add_voucher_request(self): + self.login_as_admin() study_subject = create_study_subject() url = reverse('web.views.voucher_add') + "?study_subject_id=" + str(study_subject.id) response = self.client.get(url) self.assertEqual(response.status_code, 200) def test_render_edit_voucher_request(self): + self.login_as_admin() voucher = create_voucher() response = self.client.get(reverse('web.views.voucher_edit', kwargs={'pk': voucher.id})) self.assertEqual(response.status_code, 200) + def test_render_add_voucher_request_staff(self): + self.login_as_staff() + study_subject = create_study_subject() + url = reverse('web.views.voucher_add') + "?study_subject_id=" + str(study_subject.id) + response = self.client.get(url) + self.assertEqual(response.status_code, 302) + + def test_render_edit_voucher_request_staff(self): + self.login_as_staff() + voucher = create_voucher() + response = self.client.get(reverse('web.views.voucher_edit', kwargs={'pk': voucher.id})) + self.assertEqual(response.status_code, 302) + def test_add_voucher(self): + self.login_as_admin() voucher_type = create_voucher_type() study_subject = create_study_subject() study_subject.voucher_types.add(voucher_type) @@ -56,6 +72,7 @@ class VoucherTypeViewTests(LoggedInTestCase): self.assertEqual(1, Voucher.objects.all().count()) def test_edit_voucher(self): + self.login_as_admin() voucher = create_voucher() usage_partner = create_voucher_partner() usage_partner.voucher_types.add(voucher.voucher_type) @@ -74,6 +91,7 @@ class VoucherTypeViewTests(LoggedInTestCase): self.assertEqual(1, Voucher.objects.all().count()) def test_expire_voucher_cron_job(self): + self.login_as_admin() voucher = create_voucher() voucher.status = VOUCHER_STATUS_NEW voucher.expiry_date = "2011-01-01" @@ -84,6 +102,7 @@ class VoucherTypeViewTests(LoggedInTestCase): self.assertEqual(VOUCHER_STATUS_EXPIRED, updated_voucher.status) def test_expire_voucher_cron_job_with_no_vouchers_to_update(self): + self.login_as_admin() voucher = create_voucher() voucher.status = VOUCHER_STATUS_USED voucher.expiry_date = "2011-01-01" diff --git a/smash/web/tests/view/test_voucher_type.py b/smash/web/tests/view/test_voucher_type.py index a3aa36aebd33e74b5bc734afef77b03c067900a5..7d0cf5d813beac7936155f5f736ed5a0cadd2c94 100644 --- a/smash/web/tests/view/test_voucher_type.py +++ b/smash/web/tests/view/test_voucher_type.py @@ -12,15 +12,18 @@ logger = logging.getLogger(__name__) class VoucherTypeViewTests(LoggedInTestCase): def test_render_add_voucher_type_request(self): + self.login_as_admin() response = self.client.get(reverse('web.views.voucher_type_add')) self.assertEqual(response.status_code, 200) def test_render_edit_voucher_type_request(self): + self.login_as_admin() voucher_type = create_voucher_type() response = self.client.get(reverse('web.views.voucher_type_edit', kwargs={'pk': voucher_type.id})) self.assertEqual(response.status_code, 200) def test_add_voucher_type(self): + self.login_as_admin() form_data = { 'code': "X", 'description': "y", @@ -30,3 +33,15 @@ class VoucherTypeViewTests(LoggedInTestCase): self.assertEqual(response.status_code, 302) self.assertEqual(1, VoucherType.objects.all().count()) + + def test_render_add_voucher_type_request_staff(self): + self.login_as_staff() + response = self.client.get(reverse('web.views.voucher_type_add')) + self.assertEqual(response.status_code, 302) + + def test_render_edit_voucher_type_request_staff(self): + self.login_as_staff() + voucher_type = create_voucher_type() + response = self.client.get(reverse('web.views.voucher_type_edit', kwargs={'pk': voucher_type.id})) + self.assertEqual(response.status_code, 302) + diff --git a/smash/web/tests/view/test_worker.py b/smash/web/tests/view/test_worker.py index bead17b6e0286145621d9418bdc8461242ea974b..06542ce84063bf39cd4840b63d2ca5b1e7028590 100644 --- a/smash/web/tests/view/test_worker.py +++ b/smash/web/tests/view/test_worker.py @@ -7,20 +7,35 @@ from web.forms import WorkerForm from web.models import Worker from web.models.worker_study_role import WORKER_STAFF, ROLE_CHOICES_DOCTOR, WORKER_HEALTH_PARTNER, WORKER_VOUCHER_PARTNER from web.tests import create_worker -from web.tests.functions import create_language, create_location, create_availability, format_form_field +from web.tests.functions import create_user, create_language, create_location, create_availability, format_form_field from .. import LoggedInTestCase +from web.models.constants import GLOBAL_STUDY_ID logger = logging.getLogger(__name__) class WorkerViewTests(LoggedInTestCase): def test_render_workers_list_request(self): + self.login_as_admin() + create_worker() + response = self.client.get(reverse('web.views.workers')) self.assertEqual(response.status_code, 200) + def test_render_workers_list_request_staff(self): + self.login_as_staff() + + create_worker() + + response = self.client.get(reverse('web.views.workers')) + self.assertEqual(response.status_code, 302) + def test_render_worker_type_request(self): + self.login_as_admin() + create_worker() + response = self.client.get(reverse('web.views.workers', kwargs={'worker_type': WORKER_STAFF})) self.assertEqual(response.status_code, 200) response = self.client.get(reverse('web.views.workers', kwargs={'worker_type': WORKER_HEALTH_PARTNER})) @@ -28,16 +43,39 @@ class WorkerViewTests(LoggedInTestCase): response = self.client.get(reverse('web.views.workers', kwargs={'worker_type': WORKER_VOUCHER_PARTNER})) self.assertEqual(response.status_code, 200) + def test_render_worker_type_request_staff(self): + self.login_as_staff() + + create_worker() + + response = self.client.get(reverse('web.views.workers', kwargs={'worker_type': WORKER_STAFF})) + self.assertEqual(response.status_code, 302) + response = self.client.get(reverse('web.views.workers', kwargs={'worker_type': WORKER_HEALTH_PARTNER})) + self.assertEqual(response.status_code, 302) + response = self.client.get(reverse('web.views.workers', kwargs={'worker_type': WORKER_VOUCHER_PARTNER})) + self.assertEqual(response.status_code, 302) + def test_render_add_worker_request(self): + self.login_as_admin() + response = self.client.get(reverse('web.views.worker_add', kwargs={'worker_type': WORKER_STAFF})) self.assertEqual(response.status_code, 200) + def test_render_add_worker_request_without_permissions(self): + response = self.client.get(reverse('web.views.worker_add', kwargs={'worker_type': WORKER_STAFF})) + self.assertEqual(response.status_code, 302) + def test_render_add_worker_request_for_voucher_partner(self): + self.login_as_admin() + response = self.client.get(reverse('web.views.worker_add', kwargs={'worker_type': WORKER_VOUCHER_PARTNER})) self.assertEqual(response.status_code, 200) def test_render_worker_added_request(self): - self.assertEqual(1, User.objects.all().count()) + self.assertEqual(3, Worker.objects.all().count()) + self.assertEqual(4, User.objects.all().count()) + + self.login_as_admin() language = create_language() location = create_location() @@ -49,8 +87,8 @@ class WorkerViewTests(LoggedInTestCase): self.assertEqual(response.status_code, 302) - self.assertEqual(1, Worker.objects.all().count()) - self.assertEqual(2, User.objects.all().count()) + self.assertEqual(4, Worker.objects.all().count()) + self.assertEqual(5, User.objects.all().count()) def create_add_worker_form_data(self, language, location): form_data = self.get_form_data(Worker()) @@ -92,6 +130,7 @@ class WorkerViewTests(LoggedInTestCase): return form_data def test_render_edit_worker_request(self): + self.login_as_admin() worker = create_worker() form_data = self.get_form_data(worker) @@ -104,27 +143,39 @@ class WorkerViewTests(LoggedInTestCase): updated_worker = Worker.objects.get(id=worker.id) self.assertEqual(updated_worker.last_name, form_data["last_name"]) - def test_edit_worker(self): - worker = create_worker() + def test_edit_worker_superuser(self): + self.login_as_super() - response = self.client.get(reverse('web.views.worker_edit', args=[worker.id])) + response = self.client.get(reverse('web.views.worker_edit', args=[self.super_worker.id])) self.assertEqual(response.status_code, 200) - def test_render_add_availability_request(self): - worker = create_worker() + def test_edit_worker_without_permissions(self): + self.login_as_staff() - response = self.client.get(reverse('web.views.worker_availability_add', args=[worker.id])) + response = self.client.get(reverse('web.views.worker_edit', args=[self.staff_worker.id])) + self.assertEqual(response.status_code, 302) + + def test_edit_worker_with_permissions(self): + self.login_as_admin() + + response = self.client.get(reverse('web.views.worker_edit', args=[self.admin_worker.id])) + self.assertEqual(response.status_code, 200) + + def test_render_add_availability_request(self): + self.login_as_admin() + response = self.client.get(reverse('web.views.worker_availability_add', args=[self.admin_worker.id])) self.assertEqual(response.status_code, 200) def test_render_edit_availability_request(self): - worker = create_worker() - availability = create_availability(worker) + self.login_as_admin() + + availability = create_availability(self.admin_worker) response = self.client.get(reverse('web.views.worker_availability_edit', args=[availability.id])) self.assertEqual(response.status_code, 200) def test_render_add_holiday_request(self): - worker = create_worker() + self.login_as_admin() - response = self.client.get(reverse('web.views.worker_holiday_add', args=[worker.id])) + response = self.client.get(reverse('web.views.worker_holiday_add', args=[self.admin_worker.id])) self.assertEqual(response.status_code, 200) diff --git a/smash/web/urls.py b/smash/web/urls.py index 7fd886c2015f8e689d7ba0360a30171b36ec6ba2..9535617e2553ac24623eb791e74bd2704f9ae726 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -33,6 +33,8 @@ urlpatterns = [ {'exception': Exception('Not Found')} ), + url(r'^change_password/$', views.password.change_password, name='change_password'), + #################### # APPOINTMENTS # #################### diff --git a/smash/web/utils.py b/smash/web/utils.py index 2e7d4d3133c06ebea7413150bc7476694553dccd..9e8ef001e14ee51891bde427a2c699df146ec727 100644 --- a/smash/web/utils.py +++ b/smash/web/utils.py @@ -5,7 +5,6 @@ from datetime import timedelta from web.algorithm import VerhoeffAlgorithm, LuhnAlgorithm - def is_valid_social_security_number(number): if number is not None and number != '': if len(number) != 13: diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py index fa58ba75a4ac649f8e573ce6a4cc339583d5c402..c028b0f6f9f84363d444ebe19ffa637f83d81836 100644 --- a/smash/web/views/__init__.py +++ b/smash/web/views/__init__.py @@ -6,6 +6,7 @@ from django.views.generic.base import ContextMixin from web.models.constants import GLOBAL_STUDY_ID from notifications import get_notifications from ..models import Worker, Study +from web.decorators import PermissionDecorator handler404 = 'web.views.e404_page_not_found' handler500 = 'web.views.e500_error' @@ -41,9 +42,12 @@ def wrap_response(request, template, params): def extend_context(params, request): + study = Study.get_by_id(GLOBAL_STUDY_ID) person = Worker.get_by_user(request.user) # None if AnonymousUser or no Worker associated + permissions = set() if person is not None: role = person.role + permissions = person.get_permissions(study) person = unicode(person) else: #use full name if available, username otherwise @@ -54,8 +58,9 @@ def extend_context(params, request): role = '<No worker information>' notifications = get_notifications(request.user) final_params = params.copy() - study = Study.get_by_id(GLOBAL_STUDY_ID) final_params.update({ + 'permissions' : permissions, + 'conf_perms' : permissions & PermissionDecorator.codename_groups['configuration'], 'person': person, 'role': role, 'notifications': notifications, @@ -97,3 +102,4 @@ import redcap import rooms import uploaded_files import study +import password \ No newline at end of file diff --git a/smash/web/views/configuration_item.py b/smash/web/views/configuration_item.py index 039e6290b3c198f47048800c4fb1377618a0341f..086075c46926ef9764c98603b357acd1eb39cc24 100644 --- a/smash/web/views/configuration_item.py +++ b/smash/web/views/configuration_item.py @@ -1,6 +1,7 @@ # coding=utf-8 from . import wrap_response +from web.decorators import PermissionDecorator - +@PermissionDecorator('change_configurationitem', 'configuration') def configuration_items(request): return wrap_response(request, "configuration/index.html", {}) diff --git a/smash/web/views/language.py b/smash/web/views/language.py index 99967c2e0a10c70280575275b3225c9f5b1409b5..e971d7ed224af7b8dab6ca092631688088a9d4a6 100644 --- a/smash/web/views/language.py +++ b/smash/web/views/language.py @@ -8,13 +8,16 @@ from django.views.generic import UpdateView from . import WrappedView from ..models import Language - +from web.decorators import PermissionDecorator class LanguageListView(ListView, WrappedView): model = Language context_object_name = "languages" template_name = 'languages/list.html' + @PermissionDecorator('change_language', 'configuration') + def dispatch(self, *args, **kwargs): + return super(LanguageListView, self).dispatch(*args, **kwargs) class LanguageCreateView(CreateView, WrappedView): model = Language @@ -23,6 +26,9 @@ class LanguageCreateView(CreateView, WrappedView): success_url = reverse_lazy('web.views.languages') success_message = "Language created" + @PermissionDecorator('change_language', 'configuration') + def dispatch(self, *args, **kwargs): + return super(LanguageCreateView, self).dispatch(*args, **kwargs) class LanguageDeleteView(DeleteView, WrappedView): model = Language @@ -33,6 +39,9 @@ class LanguageDeleteView(DeleteView, WrappedView): messages.success(request, "Language deleted") return super(LanguageDeleteView, self).delete(request, *args, **kwargs) + @PermissionDecorator('change_language', 'configuration') + def dispatch(self, *args, **kwargs): + return super(LanguageDeleteView, self).dispatch(*args, **kwargs) class LanguageEditView(UpdateView, WrappedView): model = Language @@ -41,3 +50,7 @@ class LanguageEditView(UpdateView, WrappedView): success_message = "Language edited" template_name = "languages/edit.html" context_object_name = "language" + + @PermissionDecorator('change_language', 'configuration') + def dispatch(self, *args, **kwargs): + return super(LanguageEditView, self).dispatch(*args, **kwargs) \ No newline at end of file diff --git a/smash/web/views/password.py b/smash/web/views/password.py new file mode 100644 index 0000000000000000000000000000000000000000..8d0ae2705d3692106efeff59a90e2082be999e04 --- /dev/null +++ b/smash/web/views/password.py @@ -0,0 +1,22 @@ +from django.contrib import messages +from django.contrib.auth import update_session_auth_hash +from django.contrib.auth.forms import PasswordChangeForm +from django.shortcuts import render, redirect +from . import wrap_response +from web.models.worker import Worker + +def change_password(request): + if request.method == 'POST': + form = PasswordChangeForm(request.user, request.POST) + if form.is_valid(): + user = form.save() + update_session_auth_hash(request, user) + messages.success(request, 'The password for {} was successfully updated!'.format(request.user)) + return redirect('web.views.workers') + else: + messages.error(request, 'Please correct the error below.') + else: + form = PasswordChangeForm(request.user) + + worker = Worker.get_by_user(request.user) + return wrap_response(request, 'doctors/change_password.html', {'form': form, 'worker': worker}) \ No newline at end of file diff --git a/smash/web/views/study.py b/smash/web/views/study.py index 75b2d71f18ee8c86c42628e1426faafde0e3d7e3..e2a37152a639437963f9cb561132d2d861befae7 100644 --- a/smash/web/views/study.py +++ b/smash/web/views/study.py @@ -7,10 +7,11 @@ from django.shortcuts import redirect, get_object_or_404 from web.forms import StudyColumnsEditForm, StudyEditForm, StudyNotificationParametersEditForm from web.models import Study from web.views import wrap_response +from web.decorators import PermissionDecorator logger = logging.getLogger(__name__) - +@PermissionDecorator('change_study', 'configuration') def study_edit(request, study_id): study = get_object_or_404(Study, id=study_id) if request.method == 'POST': diff --git a/smash/web/views/visit.py b/smash/web/views/visit.py index 96dde765288b7b54fd87468952d6a742e2fd133a..77625043f21147bc3c9b0e3cc314a9925120c2de 100644 --- a/smash/web/views/visit.py +++ b/smash/web/views/visit.py @@ -74,6 +74,7 @@ def visit_details(request, id): languages.extend(study_subject.subject.languages.all()) return wrap_response(request, 'visits/details.html', { + 'default_visit_duration' : study_subject.study.default_visit_duration_in_months, 'visit_form': visit_form, 'study_subject_form': study_subject_form, 'subject_form': subject_form, @@ -96,6 +97,7 @@ def visit_mark(request, id, as_what): def visit_add(request, subject_id=-1): if request.method == 'POST': form = VisitAddForm(request.POST, request.FILES) + args = {'form': form} if form.is_valid(): visit = form.save() return redirect('web.views.visit_details', visit.id) @@ -105,5 +107,6 @@ def visit_add(request, subject_id=-1): if len(subjects) > 0: subject = subjects[0] form = VisitAddForm(initial={'subject': subject}) + args = {'form': form, 'default_visit_duration': subject.study.default_visit_duration_in_months} - return wrap_response(request, 'visits/add.html', {'form': form}) + return wrap_response(request, 'visits/add.html', args) diff --git a/smash/web/views/voucher.py b/smash/web/views/voucher.py index d3284437be4279f414b30eebf7052877e0bfc742..e68918f6178ba28b78ee2a998dfd644b0060ab95 100644 --- a/smash/web/views/voucher.py +++ b/smash/web/views/voucher.py @@ -14,6 +14,7 @@ from web.forms import VoucherForm from web.models import Voucher, StudySubject, MailTemplate, Worker from web.models.constants import GLOBAL_STUDY_ID, VOUCHER_STATUS_NEW, VOUCHER_STATUS_EXPIRED, CRON_JOB_TIMEOUT from . import WrappedView +from web.decorators import PermissionDecorator logger = logging.getLogger(__name__) @@ -23,11 +24,14 @@ class VoucherListView(ListView, WrappedView): context_object_name = "vouchers" template_name = 'vouchers/list.html' + @PermissionDecorator('change_voucher', 'configuration') + def dispatch(self, *args, **kwargs): + return super(VoucherListView, self).dispatch(*args, **kwargs) + def voucher_types_for_study_subject(study_subject_id): return StudySubject.objects.get(id=study_subject_id).voucher_types.all() - class VoucherCreateView(CreateView, WrappedView): form_class = VoucherForm model = Voucher @@ -60,6 +64,9 @@ class VoucherCreateView(CreateView, WrappedView): kwargs['voucher_types'] = voucher_types_for_study_subject(self.request.GET.get("study_subject_id", -1)) return kwargs + @PermissionDecorator('change_voucher', 'configuration') + def dispatch(self, *args, **kwargs): + return super(VoucherCreateView, self).dispatch(*args, **kwargs) class VoucherEditView(SuccessMessageMixin, UpdateView, WrappedView): form_class = VoucherForm @@ -82,6 +89,10 @@ class VoucherEditView(SuccessMessageMixin, UpdateView, WrappedView): context['mail_templates'] = MailTemplate.get_voucher_mail_templates([]) return context + @PermissionDecorator('change_voucher', 'configuration') + def dispatch(self, *args, **kwargs): + return super(VoucherEditView, self).dispatch(*args, **kwargs) + class ExpireVouchersJob(CronJobBase): RUN_EVERY_MINUTES = 120 diff --git a/smash/web/views/voucher_type.py b/smash/web/views/voucher_type.py index 5cb45eb57245bbf5df0e1163eb274266f30e871e..1c47a8e618540971f32ae12a817e9c639511d560 100644 --- a/smash/web/views/voucher_type.py +++ b/smash/web/views/voucher_type.py @@ -8,13 +8,16 @@ from web.forms import VoucherTypeForm from web.models import VoucherType from web.models.constants import GLOBAL_STUDY_ID from . import WrappedView - +from web.decorators import PermissionDecorator class VoucherTypeListView(ListView, WrappedView): model = VoucherType context_object_name = "voucher_types" template_name = 'voucher_types/list.html' + @PermissionDecorator('change_vouchertype', 'configuration') + def dispatch(self, *args, **kwargs): + return super(VoucherTypeListView, self).dispatch(*args, **kwargs) class VoucherTypeCreateView(CreateView, WrappedView): form_class = VoucherTypeForm @@ -28,7 +31,11 @@ class VoucherTypeCreateView(CreateView, WrappedView): form.instance.study_id = GLOBAL_STUDY_ID return super(VoucherTypeCreateView, self).form_valid(form) + @PermissionDecorator('change_vouchertype', 'configuration') + def dispatch(self, *args, **kwargs): + return super(VoucherTypeCreateView, self).dispatch(*args, **kwargs) +#@PermissionDecorator('change_vouchertype', 'configuration') class VoucherTypeEditView(UpdateView, WrappedView): form_class = VoucherTypeForm model = VoucherType @@ -37,3 +44,7 @@ class VoucherTypeEditView(UpdateView, WrappedView): success_message = "Voucher type edited" template_name = "voucher_types/edit.html" context_object_name = "voucher_type" + + @PermissionDecorator('change_vouchertype', 'configuration') + def dispatch(self, *args, **kwargs): + return super(VoucherTypeEditView, self).dispatch(*args, **kwargs) diff --git a/smash/web/views/worker.py b/smash/web/views/worker.py index c2ca3cba16c1cfe96f53e26a1e3d22549bd42524..801ffa61a693a08d544f40b20cfabf9ffbf1b36a 100644 --- a/smash/web/views/worker.py +++ b/smash/web/views/worker.py @@ -10,10 +10,11 @@ from web.models.constants import WEEKDAY_CHOICES, GLOBAL_STUDY_ID, AVAILABILITY_ from web.models.worker import worker_type_by_worker from web.models.worker_study_role import WORKER_STAFF from . import wrap_response +from web.decorators import PermissionDecorator logger = logging.getLogger(__name__) - +@PermissionDecorator('change_worker', 'configuration') def worker_list(request, worker_type=WORKER_STAFF): doctors_list = Worker.get_workers_by_worker_type(worker_type, study_id=GLOBAL_STUDY_ID, ).order_by('-last_name') context = { @@ -23,7 +24,7 @@ def worker_list(request, worker_type=WORKER_STAFF): return wrap_response(request, "doctors/index.html", context) - +@PermissionDecorator('add_worker', 'configuration') def worker_add(request, worker_type): if request.method == 'POST': form = WorkerForm(request.POST, request.FILES, worker_type=worker_type) @@ -35,7 +36,7 @@ def worker_add(request, worker_type): return wrap_response(request, 'doctors/add.html', {'form': form, "worker_type": worker_type}) - +@PermissionDecorator('change_worker', 'configuration') def worker_edit(request, worker_id): worker = get_object_or_404(Worker, id=worker_id) worker_type = worker_type_by_worker(worker) @@ -59,20 +60,20 @@ def worker_edit(request, worker_id): "worker_type": worker_type }) - +@PermissionDecorator('delete_worker') def worker_disable(request, doctor_id): the_doctor = get_object_or_404(Worker, id=doctor_id) the_doctor.disable() return worker_list(request) - +@PermissionDecorator('change_worker', 'configuration') def worker_availability_delete(request, availability_id): availability = Availability.objects.filter(id=availability_id) doctor_id = availability[0].person.id availability.delete() return redirect(worker_edit, worker_id=doctor_id) - +@PermissionDecorator('change_worker', 'configuration') def worker_availability_add(request, doctor_id): worker = get_object_or_404(Worker, id=doctor_id) if request.method == 'POST': @@ -89,7 +90,7 @@ def worker_availability_add(request, doctor_id): 'doctor_name': unicode(worker) }) - +@PermissionDecorator('change_worker', 'configuration') def worker_availability_edit(request, availability_id): availability = get_object_or_404(Availability, id=availability_id) if request.method == 'POST': @@ -106,14 +107,14 @@ def worker_availability_edit(request, availability_id): 'doctor_id': availability.person_id, }) - +@PermissionDecorator('change_worker', 'configuration') def worker_holiday_delete(request, holiday_id): holiday = Holiday.objects.filter(id=holiday_id) doctor_id = holiday[0].person.id holiday.delete() return redirect(worker_edit, worker_id=doctor_id) - +@PermissionDecorator('change_worker', 'configuration') def worker_holiday_add(request, doctor_id): doctors = Worker.objects.filter(id=doctor_id) doctor = None