diff --git a/addons/website_forum/__manifest__.py b/addons/website_forum/__manifest__.py index c3b2ee4b982..e7e3423035c 100644 --- a/addons/website_forum/__manifest__.py +++ b/addons/website_forum/__manifest__.py @@ -24,6 +24,7 @@ Ask questions, get answers, no distractions 'views/website_forum_profile.xml', 'views/ir_qweb.xml', 'security/ir.model.access.csv', + 'security/website_forum_security.xml', 'data/badges_question.xml', 'data/badges_answer.xml', 'data/badges_participation.xml', diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index 6ad0af1f2f1..e14ab54a73f 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -48,19 +48,26 @@ class WebsiteForum(WebsiteProfile): return request.render("website_forum.forum_all", {'forums': forums}) @http.route('/forum/new', type='json', auth="user", methods=['POST'], website=True) - def forum_create(self, forum_name="New Forum", forum_mode="questions", add_menu=False): - forum_id = request.env['forum.forum'].create({ + def forum_create(self, forum_name="New Forum", forum_mode="questions", forum_privacy="public", forum_privacy_group=False, add_menu=False): + forum = { 'name': forum_name, 'mode': forum_mode, + 'privacy': forum_privacy, 'website_id': request.website.id, - }) + } + if forum_privacy == 'private' and forum_privacy_group: + forum['authorized_group_id'] = forum_privacy_group + forum_id = request.env['forum.forum'].create(forum) if add_menu: - request.env['website.menu'].create({ + group = [int(forum_privacy_group)] if forum_privacy == 'private' else [request.env.ref('base.group_portal').id, request.env.ref('base.group_user').id] + menu_id = request.env['website.menu'].create({ 'name': forum_name, 'url': "/forum/%s" % slug(forum_id), 'parent_id': request.website.menu_id.id, 'website_id': request.website.id, + 'group_ids': [(6, 0, group)] }) + forum_id.menu_id = menu_id return "/forum/%s" % slug(forum_id) def sitemap_forum(env, rule, qs): diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 9f17605b690..4b70b2df39f 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -34,6 +34,14 @@ class Forum(models.Model): ('discussions', 'Discussions')], string='Forum Mode', required=True, default='questions', help='Questions mode: only one answer allowed\n Discussions mode: multiple answers allowed') + privacy = fields.Selection([ + ('public', 'Public'), + ('connected', 'Signed In'), + ('private', 'Some users')], + help="Public: Forum is pubic\nSigned In: Forum is visible for signed in users\nSome users: Forum and their content are hidden for non members of selected group", + default='public') + authorized_group_id = fields.Many2one('res.groups', 'Authorized Group') + menu_id = fields.Many2one('website.menu', 'Menu', copy=False) active = fields.Boolean(default=True) faq = fields.Html('Guidelines', default=_get_default_faq, translate=html_translate, sanitize=False) description = fields.Text('Description', translate=True) @@ -153,6 +161,20 @@ class Forum(models.Model): return super(Forum, self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)).create(values) def write(self, vals): + if 'privacy' in vals: + if not vals['privacy']: + # The forum is neither public, neither private, remove menu to avoid conflict + self.menu_id.unlink() + elif vals['privacy'] == 'public': + # The forum is public, the menu must be also public + vals['authorized_group_id'] = False + self.menu_id.write({'group_ids': [(5, 0, 0)]}) + elif vals['privacy'] == 'connected': + vals['authorized_group_id'] = False + self.menu_id.write({'group_ids': [(6, 0, [self.env.ref('base.group_portal').id, self.env.ref('base.group_user').id])]}) + if 'authorized_group_id' in vals and vals['authorized_group_id']: + self.menu_id.write({'group_ids': [(6, 0, [vals['authorized_group_id']])]}) + res = super(Forum, self).write(vals) if 'active' in vals: # archiving/unarchiving a forum does it on its posts, too diff --git a/addons/website_forum/security/website_forum_security.xml b/addons/website_forum/security/website_forum_security.xml new file mode 100644 index 00000000000..6908c0fb102 --- /dev/null +++ b/addons/website_forum/security/website_forum_security.xml @@ -0,0 +1,74 @@ + + + + Website forum: Public user can only access to public forum + + [('privacy', '=', 'public')] + + + + Website forum: User can only access to public (or authorized) forum + + [ + '|', + ('privacy', 'in', ['public', 'connected']), + '&', + ('privacy', '=', 'private'), + ('authorized_group_id', 'in', user.groups_id.ids)] + + + + Website forum: Website designer can create private forum + + [(1, '=', 1)] + + + + + + + + Website forum: All access for manager + + [(1, '=', 1)] + + + + + Website forum post: Public user can only access to public post + + [('forum_id.privacy', '=', 'public')] + + + + Website forum post: User can only access to public (or authorized) post + + ['|', ('forum_id.privacy', 'in', ['public', 'connected']), '&', ('forum_id.privacy', '=', 'private'), ('forum_id.authorized_group_id', 'in', user.groups_id.ids)] + + + + Website forum post : All access for manager + + [(1, '=', 1)] + + + + + Website forum tag: Public user can only access to tag linked to public forum + + [('forum_id.privacy', '=', 'public')] + + + + Website forum tag: User can only access to tag linked to public (or authorized) forum + + ['|', ('forum_id.privacy', 'in', ['public', 'connected']), '&', ('forum_id.privacy', '=', 'private'), ('forum_id.authorized_group_id', 'in', user.groups_id.ids)] + + + + Website forum tag : Manager user can access to all tags + + [(1, '=', 1)] + + + diff --git a/addons/website_forum/static/src/js/website_forum.editor.js b/addons/website_forum/static/src/js/website_forum.editor.js index 2f6d61791c8..74072c592b4 100644 --- a/addons/website_forum/static/src/js/website_forum.editor.js +++ b/addons/website_forum/static/src/js/website_forum.editor.js @@ -12,6 +12,9 @@ var ForumCreateDialog = Dialog.extend({ ['/website_forum/static/src/xml/website_forum_templates.xml'] ), template: 'website_forum.add_new_forum', + events: _.extend({}, Dialog.prototype.events, { + 'change input[name="privacy"]': '_onPrivacyChanged', + }), /** * @override @@ -36,19 +39,67 @@ var ForumCreateDialog = Dialog.extend({ }); this._super(parent, options); }, + start: function () { + var self = this; + return this._super.apply(this, arguments).then(function () { + var $input = self.$('#group_id'); + $input.select2({ + width: '100%', + allowClear: true, + formatNoMatches: false, + multiple: false, + selection_data: false, + fill_data: function (query, data) { + var that = this; + var tags = {results: []}; + _.each(data, function (obj) { + if (that.matcher(query.term, obj.display_name)) { + tags.results.push({id: obj.id, text: obj.display_name}); + } + }); + query.callback(tags); + }, + query: function (query) { + var that = this; + // fetch data only once and store it + if (!this.selection_data) { + self._rpc({ + model: 'res.groups', + method: 'search_read', + args: [[], ['display_name']], + }).then(function (data) { + that.fill_data(query, data); + that.selection_data = data; + }); + } else { + this.fill_data(query, this.selection_data); + } + } + }); + }); + }, onCreateClick: function () { var $dialog = this.$el; - var forumName = $dialog.find('input[name=forum_name]').val();; - if (!forumName) { + var $forumName = $dialog.find('input[name=forum_name]'); + if (!$forumName.val()) { + $forumName.addClass('border-danger'); + return; + } + var $forumPrivacyGroup = $dialog.find('input[name=group_id]'); + var forumPrivacy = $dialog.find('input:radio[name=privacy]:checked').val(); + if (forumPrivacy === 'private' && !$forumPrivacyGroup.val()) { + this.$("#group-required").removeClass('d-none'); return; } var addMenu = ($dialog.find('input[type="checkbox"]').is(':checked')); - var forumMode = $dialog.find('input[type="radio"]:checked').val(); + var forumMode = $dialog.find('input:radio[name=mode]:checked').val(); return this._rpc({ route: '/forum/new', params: { - forum_name: forumName, + forum_name: $forumName.val(), forum_mode: forumMode, + forum_privacy: forumPrivacy, + forum_privacy_group: $forumPrivacyGroup.val(), add_menu: addMenu || "", }, }).then(function (url) { @@ -56,6 +107,12 @@ var ForumCreateDialog = Dialog.extend({ return new Promise(function () {}); }); }, + /** + * @private + */ + _onPrivacyChanged: function (ev) { + this.$('.show_visibility_group').toggleClass('d-none', ev.target.value !== 'private'); + }, }); WebsiteNewMenu.include({ diff --git a/addons/website_forum/static/src/xml/website_forum_templates.xml b/addons/website_forum/static/src/xml/website_forum_templates.xml index 0d3ce2407d0..afe95135158 100644 --- a/addons/website_forum/static/src/xml/website_forum_templates.xml +++ b/addons/website_forum/static/src/xml/website_forum_templates.xml @@ -3,7 +3,7 @@
- +
@@ -13,7 +13,8 @@
- +
@@ -25,6 +26,28 @@
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +

Please fill in this field

+
+
+
diff --git a/addons/website_forum/views/forum.xml b/addons/website_forum/views/forum.xml index a0f73ded162..c01640354c9 100644 --- a/addons/website_forum/views/forum.xml +++ b/addons/website_forum/views/forum.xml @@ -42,31 +42,40 @@
- - + + + + - - + + + + + + + - - - - - - - - + + + + + + + + + + @@ -103,9 +112,6 @@ - - -
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index bf4800285a0..64621d6e765 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -1608,7 +1608,11 @@ diff --git a/addons/website_slides_forum/__manifest__.py b/addons/website_slides_forum/__manifest__.py index c5452a836b2..5199f0bcbf1 100644 --- a/addons/website_slides_forum/__manifest__.py +++ b/addons/website_slides_forum/__manifest__.py @@ -13,6 +13,7 @@ ], 'data': [ 'security/ir.model.access.csv', + 'security/website_slides_forum_security.xml', 'views/forum_views.xml', 'views/slide_channel_views.xml', 'views/website_slides_menu_views.xml', diff --git a/addons/website_slides_forum/models/forum.py b/addons/website_slides_forum/models/forum.py index a08d744ee49..30a0c4d9e1c 100644 --- a/addons/website_slides_forum/models/forum.py +++ b/addons/website_slides_forum/models/forum.py @@ -7,8 +7,9 @@ from odoo import api, fields, models class Forum(models.Model): _inherit = 'forum.forum' - slide_channel_ids = fields.One2many('slide.channel', 'forum_id', 'Courses') - slide_channel_id = fields.Many2one('slide.channel', 'Course', compute='_compute_slide_channel_id') + slide_channel_ids = fields.One2many('slide.channel', 'forum_id', 'Courses', help="Edit the course linked to this forum on the course form.") + slide_channel_id = fields.Many2one('slide.channel', 'Course', compute='_compute_slide_channel_id', store=True) + visibility = fields.Selection(related='slide_channel_id.visibility', help="Forum linked to a Course, the visibility is the one applied on the course.") @api.depends('slide_channel_ids') def _compute_slide_channel_id(self): diff --git a/addons/website_slides_forum/models/slide_channel.py b/addons/website_slides_forum/models/slide_channel.py index 3406ed95ee6..fec0d88564c 100644 --- a/addons/website_slides_forum/models/slide_channel.py +++ b/addons/website_slides_forum/models/slide_channel.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import fields, models +from odoo import api, fields, models class Channel(models.Model): @@ -24,3 +24,23 @@ class Channel(models.Model): action['domain'] = [('forum_id', '=', self.forum_id.id)] return action + + @api.model + def create(self, vals): + channel = super(Channel, self.with_context(mail_create_nosubscribe=True)).create(vals) + if channel.forum_id: + channel.forum_id.privacy = False + return channel + + def write(self, vals): + old_forum = self.forum_id + + res = super(Channel, self).write(vals) + if 'forum_id' in vals: + self.forum_id.privacy = False + if old_forum != self.forum_id: + old_forum.write({ + 'privacy': 'private', + 'authorized_group_id': self.env.ref('website_slides.group_website_slides_officer').id, + }) + return res diff --git a/addons/website_slides_forum/security/website_slides_forum_security.xml b/addons/website_slides_forum/security/website_slides_forum_security.xml new file mode 100644 index 00000000000..3ca12ec8b36 --- /dev/null +++ b/addons/website_slides_forum/security/website_slides_forum_security.xml @@ -0,0 +1,41 @@ + + + + Website forum: User can only access to forum related to followed courses + + ['&', ('slide_channel_ids.website_published', '=', True), '|', ('slide_channel_ids.visibility', '=', 'public'), ('slide_channel_ids.partner_ids', 'in', user.partner_id.id)] + + + + Website forum: website slides officer can access all forum + + [(1, '=', 1)] + + + + + Website forum post: User can only access to post linked to forum related to followed courses + + ['&', ('forum_id.slide_channel_ids.website_published', '=', True), '|', ('forum_id.slide_channel_ids.visibility', '=', 'public'), ('forum_id.slide_channel_ids.partner_ids', 'in', user.partner_id.id)] + + + + Website forum post: website slides officer can access all post + + [(1, '=', 1)] + + + + + Website slides forum tag: User can only access to tag linked to forum related to followed courses + + ['&', ('forum_id.slide_channel_ids.website_published', '=', True), '|', ('forum_id.slide_channel_ids.visibility', '=', 'public'), ('forum_id.slide_channel_ids.partner_ids', 'in', user.partner_id.id)] + + + + Website slides forum tag: website slides officer can access all tag + + [(1, '=', 1)] + + + diff --git a/addons/website_slides_forum/views/forum_views.xml b/addons/website_slides_forum/views/forum_views.xml index 08c05b7bba5..d0acd7037e6 100644 --- a/addons/website_slides_forum/views/forum_views.xml +++ b/addons/website_slides_forum/views/forum_views.xml @@ -10,6 +10,15 @@ + + {'invisible': [('slide_channel_id', '!=', False)], 'required': [('slide_channel_id', '!=', 'False')]} + + + {'invisible': ['|', ('privacy', '!=', 'private'), ('slide_channel_id', '!=', False)], 'required': [('privacy', '=', 'private')]} + + + +