commit
2be9d45884
@ -19,6 +19,7 @@ Motions:
|
||||
Core:
|
||||
- No reload on logoff. OpenSlides is now a full single page
|
||||
application [#3172].
|
||||
- Adding support for choosing image files as logos.
|
||||
|
||||
Users:
|
||||
- User without permission to see users can now see agenda item speakers,
|
||||
|
@ -15,6 +15,7 @@ INPUT_TYPE_MAPPING = {
|
||||
'colorpicker': str,
|
||||
'datetimepicker': int,
|
||||
'majorityMethod': str,
|
||||
'logo': dict,
|
||||
}
|
||||
|
||||
|
||||
@ -104,6 +105,19 @@ class ConfigHandler:
|
||||
if not isinstance(comment['public'], bool):
|
||||
raise ConfigError(_('public property has to be bool.'))
|
||||
|
||||
if config_variable.input_type == 'logo':
|
||||
if not isinstance(value, dict):
|
||||
raise ConfigError(_('logo has to be a dict.'))
|
||||
whitelist = (
|
||||
'path',
|
||||
'display_name',
|
||||
)
|
||||
for required_entry in whitelist:
|
||||
if required_entry not in value:
|
||||
raise ConfigError(_('{} has to be given.'.format(required_entry)))
|
||||
if not isinstance(value[required_entry], str):
|
||||
raise ConfigError(_('{} has to be a string.'.format(required_entry)))
|
||||
|
||||
# Save the new value to the database.
|
||||
try:
|
||||
db_value = ConfigStore.objects.get(key=key)
|
||||
|
@ -209,3 +209,21 @@ def get_config_variables():
|
||||
weight=201,
|
||||
group='Projector',
|
||||
hidden=True)
|
||||
|
||||
# Logos.
|
||||
yield ConfigVariable(
|
||||
name='logos_available',
|
||||
default_value=['logo_projector_main'],
|
||||
weight=300,
|
||||
group='Logo',
|
||||
hidden=True)
|
||||
|
||||
yield ConfigVariable(
|
||||
name='logo_projector_main',
|
||||
default_value={
|
||||
'display_name': 'Main projector logo',
|
||||
'path': ''},
|
||||
input_type='logo',
|
||||
weight=301,
|
||||
group='Logo',
|
||||
hidden=True)
|
||||
|
25
openslides/core/migrations/0005_auto_20170412_1258.py
Normal file
25
openslides/core/migrations/0005_auto_20170412_1258.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.5 on 2017-04-12 10:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_auto_20170215_1624'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='configstore',
|
||||
options={
|
||||
'default_permissions': (),
|
||||
'permissions': (
|
||||
('can_manage_config', 'Can manage configuration'),
|
||||
('can_manage_logos', 'Can manage logos')
|
||||
)
|
||||
},
|
||||
),
|
||||
]
|
@ -257,7 +257,8 @@ class ConfigStore(RESTModelMixin, models.Model):
|
||||
class Meta:
|
||||
default_permissions = ()
|
||||
permissions = (
|
||||
('can_manage_config', 'Can manage configuration'),)
|
||||
('can_manage_config', 'Can manage configuration'),
|
||||
('can_manage_logos', 'Can manage logos'))
|
||||
|
||||
@classmethod
|
||||
def get_collection_string(cls):
|
||||
|
@ -580,6 +580,49 @@ angular.module('OpenSlidesApp.core', [
|
||||
}
|
||||
])
|
||||
|
||||
.factory('Logos', [
|
||||
'Config',
|
||||
'gettext',
|
||||
function (Config, gettext) {
|
||||
return {
|
||||
getKeys: function () {
|
||||
return Config.get('logos_available').value;
|
||||
},
|
||||
getAll: function () {
|
||||
var self = this;
|
||||
return _.map(this.getKeys(), function (key) {
|
||||
return self.getFromKey(key);
|
||||
});
|
||||
},
|
||||
getFromKey: function (key) {
|
||||
var config = Config.get(key).value;
|
||||
config.key = key;
|
||||
return config;
|
||||
},
|
||||
isMediafileUsedAsLogo: function (mediafile) {
|
||||
return _.find(this.getAll(), function (logoPlaceholder) {
|
||||
return logoPlaceholder.path === mediafile.mediafileUrl;
|
||||
});
|
||||
},
|
||||
canMediafileBeUsedAsLogo: function (mediafile) {
|
||||
return mediafile.is_image;
|
||||
},
|
||||
setMediafile: function (key, mediafile) {
|
||||
var config = Config.get(key);
|
||||
if (!mediafile || mediafile.canBeUsedAsLogo()) {
|
||||
config.value.path = mediafile ? mediafile.mediafileUrl : '';
|
||||
Config.save(key);
|
||||
}
|
||||
},
|
||||
getLogosForMediafile: function (mediafile) {
|
||||
return _.filter(this.getAll(), function (logoPlaceholder) {
|
||||
return logoPlaceholder.path === mediafile.mediafileUrl;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('Tag', [
|
||||
'DS',
|
||||
function(DS) {
|
||||
|
@ -150,7 +150,8 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
|
||||
'slides',
|
||||
'Config',
|
||||
'ProjectorID',
|
||||
function($scope, $location, $timeout, Projector, slides, Config, ProjectorID) {
|
||||
'Logos',
|
||||
function($scope, $location, $timeout, Projector, slides, Config, ProjectorID, Logos) {
|
||||
var projectorId = ProjectorID();
|
||||
|
||||
$scope.broadcast = 0;
|
||||
@ -243,6 +244,11 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
|
||||
}
|
||||
});
|
||||
|
||||
$scope.getLogo = function (key) {
|
||||
var logo = Logos.getFromKey(key);
|
||||
return logo ? logo.path : void 0;
|
||||
};
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
if ($scope.broadcastDeregister) {
|
||||
$scope.broadcastDeregister();
|
||||
|
@ -33,7 +33,8 @@
|
||||
|
||||
|
||||
<div id="header">
|
||||
<img ng-if="config('projector_enable_logo')" id="logo" src="/static/img/logo-projector.png" alt="OpenSlides" />
|
||||
<img ng-if="config('projector_enable_logo')" id="logo" alt="OpenSlides"
|
||||
ng-src="{{ getLogo('logo_projector_main') || '/static/img/logo-projector.png' }}"/>
|
||||
<div ng-if="config('projector_enable_title')" id="eventdata">
|
||||
<div class="title" ng-class="{ 'titleonly': !config('general_event_description') }"
|
||||
ng-bind-html="config('general_event_name')"></div>
|
||||
|
@ -632,7 +632,13 @@ class ConfigViewSet(ViewSet):
|
||||
# enabled.
|
||||
result = self.request.user.is_authenticated() or anonymous_is_enabled()
|
||||
elif self.action in ('partial_update', 'update'):
|
||||
result = has_perm(self.request.user, 'core.can_manage_config')
|
||||
# The user needs 'core.can_manage_logos' for all config values
|
||||
# starting with 'logo'. For all other config values th euser needs
|
||||
# the default permissions 'core.can_manage_config'.
|
||||
if self.kwargs['pk'].startswith('logo'):
|
||||
result = has_perm(self.request.user, 'core.can_manage_logos')
|
||||
else:
|
||||
result = has_perm(self.request.user, 'core.can_manage_config')
|
||||
else:
|
||||
result = False
|
||||
return result
|
||||
|
@ -22,8 +22,9 @@ angular.module('OpenSlidesApp.mediafiles.list', [
|
||||
'User',
|
||||
'Mediafile',
|
||||
'MediafileForm',
|
||||
'Logos',
|
||||
function ($http, $scope, gettext, ngDialog, osTableFilter, osTableSort,
|
||||
ProjectionDefault, Projector, User, Mediafile, MediafileForm) {
|
||||
ProjectionDefault, Projector, User, Mediafile, MediafileForm, Logos) {
|
||||
Mediafile.bindAll({}, $scope, 'mediafiles');
|
||||
User.bindAll({}, $scope, 'users');
|
||||
$scope.$watch(function() {
|
||||
@ -250,6 +251,22 @@ angular.module('OpenSlidesApp.mediafiles.list', [
|
||||
{playing: !mediafile.playing}
|
||||
);
|
||||
};
|
||||
|
||||
/** Logos **/
|
||||
$scope.logos = Logos.getAll();
|
||||
$scope.toggleLogo = function (mediafile, logo) {
|
||||
if (!$scope.hasLogo(mediafile, logo)) {
|
||||
Logos.setMediafile(logo.key, mediafile);
|
||||
} else {
|
||||
Logos.setMediafile(logo.key);
|
||||
}
|
||||
};
|
||||
$scope.hasLogo = function (mediafile, logo) {
|
||||
var allUrls = _.map(mediafile.getLogos(), function (logo) {
|
||||
return logo.path;
|
||||
});
|
||||
return _.includes(allUrls, logo.path);
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -12,7 +12,8 @@ angular.module('OpenSlidesApp.mediafiles.resources', [
|
||||
'DS',
|
||||
'gettext',
|
||||
'jsDataModel',
|
||||
function (DS, gettext, jsDataModel) {
|
||||
'Logos',
|
||||
function (DS, gettext, jsDataModel, Logos) {
|
||||
var name = 'mediafiles/mediafile';
|
||||
return DS.defineResource({
|
||||
name: name,
|
||||
@ -48,6 +49,15 @@ angular.module('OpenSlidesApp.mediafiles.resources', [
|
||||
}
|
||||
});
|
||||
},
|
||||
isUsedAsLogo: function () {
|
||||
return Logos.isMediafileUsedAsLogo(this);
|
||||
},
|
||||
canBeUsedAsLogo: function () {
|
||||
return Logos.canMediafileBeUsedAsLogo(this);
|
||||
},
|
||||
getLogos: function () {
|
||||
return Logos.getLogosForMediafile(this);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
is_pdf: ['filetype', function (filetype) {
|
||||
|
@ -282,6 +282,8 @@
|
||||
<div class="spacer-right"> <!-- horizontal block -->
|
||||
<i ng-style="{'visibility': mediafile.hidden ? 'visible' : 'hidden'}" class="fa fa-lock fa-lg"
|
||||
title="{{ 'Is hidden' | translate }}"></i>
|
||||
<i ng-style="{'visibility': mediafile.isUsedAsLogo() ? 'visible' : 'hidden'}" class="fa fa-picture-o fa-lg spacer-left"
|
||||
title="{{ 'Is used as a logo' | translate }}" os-perms="core.can_manage_logos"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div> <!-- vertical block -->
|
||||
@ -312,7 +314,41 @@
|
||||
<div><i class="fa fa-upload"></i> {{ mediafile.timestamp | date:'yyyy-MM-dd HH:mm:ss' }}</div>
|
||||
</small>
|
||||
</div>
|
||||
<div style="width: 40%;" class="pull-right optional"></div>
|
||||
<div style="width: 40%;" class="pull-right optional">
|
||||
<!-- Logo placeholder dropdown for manage user -->
|
||||
<div os-perms="core.can_manage_logos"
|
||||
ng-mouseover="mediafile.logoHover=true"
|
||||
ng-mouseleave="mediafile.logoHover=false"
|
||||
ng-show="mediafile.canBeUsedAsLogo()">
|
||||
<span uib-dropdown>
|
||||
<span id="dropdownLogo{{ mediafile.id }}" class="pointer nobr"
|
||||
uib-dropdown-toggle uib-tooltip="{{ 'Manage logos' | translate }}"
|
||||
tooltip-class="nobr">
|
||||
<span ng-if="!mediafile.isUsedAsLogo()" ng-show="mediafile.hover">
|
||||
<i class="fa fa-picture-o"></i>
|
||||
<i class="fa fa-plus"></i>
|
||||
</span>
|
||||
<span ng-if="mediafile.isUsedAsLogo()">
|
||||
<i class="fa fa-picture-o spacer-right"></i>
|
||||
<span ng-repeat="logo in mediafile.getLogos()">
|
||||
<small>
|
||||
{{ logo.display_name }}<span ng-if="!$last">,</span>
|
||||
</small>
|
||||
</span>
|
||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="mediafile.logoHover"></i>
|
||||
</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownLogos{{ mediafile.id }}">
|
||||
<li ng-repeat="logo in logos">
|
||||
<a href ng-click="toggleLogo(mediafile, logo)">
|
||||
<i class="fa fa-check" ng-if="hasLogo(mediafile, logo)"></i>
|
||||
{{ logo.display_name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- end data row -->
|
||||
|
@ -38,6 +38,7 @@ def create_builtin_groups_and_admin(**kwargs):
|
||||
'assignments.can_nominate_self',
|
||||
'assignments.can_see',
|
||||
'core.can_manage_config',
|
||||
'core.can_manage_logos',
|
||||
'core.can_manage_projector',
|
||||
'core.can_manage_tags',
|
||||
'core.can_manage_chat',
|
||||
@ -113,6 +114,7 @@ def create_builtin_groups_and_admin(**kwargs):
|
||||
permission_dict['core.can_see_frontpage'],
|
||||
permission_dict['core.can_see_projector'],
|
||||
permission_dict['core.can_manage_config'],
|
||||
permission_dict['core.can_manage_logos'],
|
||||
permission_dict['core.can_manage_projector'],
|
||||
permission_dict['core.can_manage_tags'],
|
||||
permission_dict['core.can_use_chat'],
|
||||
|
Loading…
Reference in New Issue
Block a user