Commit 7d04329c authored by alexandre's avatar alexandre

Permission editing almost there

parent 0c6d60ed
......@@ -8,6 +8,7 @@ from guardian.shortcuts import assign_perm, get_users_with_perms
from django.contrib.auth.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField()
......@@ -25,20 +26,26 @@ class AttachmentSerializer(serializers.HyperlinkedModelSerializer):
# read_only_fields = ('attachment',)
class PermissionsField(serializers.Serializer):
class PermissionListSerializer(serializers.ListSerializer):
def to_representation(self, obj):
perms = get_users_with_perms(obj, attach_perms=True)
return [{"username": k.username, "permissions": v} for k, v in perms.items()]
def to_internal_value(self, data):
# return data
# I don't understand why I can't just return data
return {"permissions": data}
class PermissionSerializer(serializers.Serializer):
class Meta:
list_serializer_class = PermissionListSerializer
class ScoreSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField()
tags = TagListSerializerField()
permissions = PermissionsField(source="*")
permissions = PermissionSerializer(source="*", many=True)
class Meta:
model = Score
......@@ -50,9 +57,13 @@ class ScoreSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
return instance
def update(self, instance, validated_data):
import ipdb; ipdb.set_trace()
instance = super(ScoreSerializer, self).update(instance, validated_data)
permissions = validated_data["permissions"]
for username, perms in permissions.items():
for i in permissions:
username = i.get("username")
perms = i.get("permissions")
user = User.objects.get(username=username)
for perm in perms:
assign_perm(perm, user, instance)
......
......@@ -956,3 +956,8 @@ li li li li li li li li li li li li li li form { color: var(--color-14); }
}
#help.is-collapsed .help__content { display: none; }
.permission-list label { display: inline; }
......@@ -1313,12 +1313,50 @@ window.W = window.W || {};
W.PermissionItemView = Backbone.Marionette.View.extend({
tagName: 'li',
template: '#permission-item-template',
ui: {
'checkbox': 'input',
},
triggers: {
'change @ui.checkbox': 'change:permissions',
},
initialize: function () {
this.$el.attr("data-username", this.model.get("username"))
},
});
W.PermissionView = Backbone.Marionette.CollectionView.extend({
tagName: 'ol',
attributes: { class: 'permission-list' },
childView: W.PermissionItemView,
childViewEvents: {
'change:permissions': 'changePermissions',
},
changePermissions: function(event) {
var perms = [];
this.$el.find("li").each(function() {
var data = {};
data.username = $(this).attr("data-username");
data.permissions = [];
$(this).find('[type="checkbox"]:checked').each(function(){
data.permissions.push($(this).val());
});
perms.push(data);
});
this.collection.score.save({permissions: perms}, {silent: true})
},
});
......
ul.autocomplete {
display: none;
position: absolute;
background-color: #f8f8f8;
margin: 0;
padding: 3px 0;
}
ul.autocomplete li {
list-style: none;
margin: 0;
padding: 5px 7px;
}
ul.autocomplete li.active, ul.autocomplete li:hover {
cursor: pointer;
background-color: #d3d3d3;
}
ul.autocomplete li a {
color: #3d3d3d;
text-decoration: none;
}
var AutoCompleteItemView = Backbone.View.extend({
tagName: "li",
template: _.template('<a href="#"><%= label %></a>'),
events: {
"click": "select"
},
initialize: function(options) {
this.options = options;
},
render: function () {
this.$el.html(this.template({
"label": this.highlight(this.model.label())
}));
return this;
},
highlight: function (label) { // tkes, highlight keyword in result
var op = this.options.parent;
if (label && op.highlight && op.currentText) {
label = label.replace(
new RegExp(this.escapeRegExp(op.currentText), "gi"),
function (matched) {
return $('<b>').addClass(op.highlight).html(matched);
}
);
}
return label;
},
escapeRegExp: function(str) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
return String(str).replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
},
select: function () {
this.options.parent.hide().select(this.model);
return false;
}
});
var AutoCompleteView = Backbone.View.extend({
tagName: "ul",
className: "autocomplete",
wait: 300,
queryParameter: "query",
minKeywordLength: 2,
currentText: "",
itemView: AutoCompleteItemView,
highlight: "",
initialize: function (options) {
_.extend(this, options);
this.filter = _.debounce(this.filter, this.wait);
},
render: function () {
// disable the native auto complete functionality
this.input.attr("autocomplete", "off");
this.$el.width(this.input.outerWidth());
this.input
.keyup(_.bind(this.keyup, this))
.keydown(_.bind(this.keydown, this))
.after(this.$el)
.blur($.proxy(this.blur, this))
;
return this;
},
keydown: function (event) {
if (event.keyCode == 38) return this.move(-1);
if (event.keyCode == 40) return this.move(+1);
if (event.keyCode == 13) return this.onEnter();
if (event.keyCode == 27) return this.hide();
},
blur: function() {
this.hide();
},
keyup: function () {
var keyword = this.input.val();
if (this.isChanged(keyword)) {
if (this.isValid(keyword)) {
this.filter(keyword);
} else {
this.hide()
}
this.currentText = keyword; // tkes, moved here from loadResult
}
},
filter: function (keyword) {
var keyword = keyword.toLowerCase();
if (this.model.url) {
var parameters = {};
parameters[this.queryParameter] = keyword;
this.model.fetch({
success: _.bind(function () { // tkes, _.bind instead of .bind()
this.loadResult(this.model.models, keyword);
}, this),
data: parameters,
// tkes, some more params
cache: (typeof this.model.cache != 'undefined') ? this.model.cache : undefined,
dataType: (this.model.datatype) ? this.model.datatype : undefined,
jsonpCallback: (this.model.callback) ? this.model.callback : undefined
});
} else {
this.loadResult(this.model.filter(function (model) {
return model.label().toLowerCase().indexOf(keyword) !== -1
}), keyword);
}
},
isValid: function (keyword) {
return keyword.length > this.minKeywordLength
},
isChanged: function (keyword) {
return this.currentText != keyword;
},
move: function (position) {
var current = this.$el.children(".active"),
siblings = this.$el.children(),
index = current.index() + position;
if (siblings.eq(index).length) {
current.removeClass("active");
siblings.eq(index).addClass("active");
}
return false;
},
onEnter: function () {
this.$el.children(".active").click();
return false;
},
loadResult: function (model, keyword) {
this.show().reset();
if (model.length) {
_.forEach(model, this.addItem, this);
this.show();
} else {
this.hide();
}
},
addItem: function (model) {
this.$el.append(new this.itemView({
model: model,
parent: this
}).render().$el);
},
select: function (model) {
var label = model.label();
this.input.val(label);
this.currentText = label;
this.onSelect(model);
},
reset: function () {
this.$el.empty();
return this;
},
hide: function () {
this.$el.hide();
return this;
},
show: function () {
this.$el.show();
return this;
},
// callback definitions
onSelect: function () {}
});
ok
<%- username %><br>
<input type="checkbox" value="view_score" name="view_score"
<% if (_.indexOf(permissions, "view_score")) { %> checked <% } %>
/>
<label>Peut voir</label>
<input type="checkbox" value="change_score" name="change_score"
<% if (_.indexOf(permissions, "change_score")) { %> checked <% } %>
/>
<label>Peut éditer</label>
<span>ne plus partager</span>
<br>
<br>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment