diff --git a/client/src/components/comments/Comment.js b/client/src/components/comments/Comment.js
index ff2a58e0..bcf1d823 100644
--- a/client/src/components/comments/Comment.js
+++ b/client/src/components/comments/Comment.js
@@ -171,7 +171,7 @@ const Comment = ({ comment, isDraft, callback }) => {
const generateDropdownOptions = () => {
if (userRole) {
let deleteOption =
- userRole.delete.postComment &&
+ userRole.delete.comment &&
(comment.postedBy._id == user._id ||
comment.postedBy._id == user.anonymousId)
? {
@@ -180,7 +180,7 @@ const Comment = ({ comment, isDraft, callback }) => {
}
: null;
let editOption =
- userRole.edit.postComment &&
+ userRole.edit.comment &&
(comment.postedBy._id == user._id ||
comment.postedBy._id == user.anonymousId)
? { onClick: handleEdit, label: "Edit Comment" }
@@ -277,21 +277,25 @@ const Comment = ({ comment, isDraft, callback }) => {
>
) : (
<>
-
-
- {
- toggleReply(true);
- }}
- >
- Reply
-
+ {userRole.participation.reactions && (
+
+ )}
+
+ {userRole.publish.reply && (
+ {
+ toggleReply(true);
+ }}
+ >
+ Reply
+
+ )}
>
)}
diff --git a/client/src/components/comments/CommentReply.js b/client/src/components/comments/CommentReply.js
index cb68acd0..5e07cf87 100644
--- a/client/src/components/comments/CommentReply.js
+++ b/client/src/components/comments/CommentReply.js
@@ -232,12 +232,14 @@ const CommentReply = ({
>
) : (
<>
-
+ {userRole.participation.reactions && (
+
+ )}
>
)}
diff --git a/client/src/components/comments/CommentView.js b/client/src/components/comments/CommentView.js
index 4c27b188..ca679455 100644
--- a/client/src/components/comments/CommentView.js
+++ b/client/src/components/comments/CommentView.js
@@ -58,7 +58,7 @@ const CommentView = ({ classroomName }) => {
// const setUserRole = useContext(UserRoleDispatchContext);
const userRole = useContext(UserRoleContext);
- // console.log("Comment View Role Object: ", userRole);
+ console.log("Comment View Role Object: ", userRole);
const handleVote = (voteAnswer) => {
var pa = pollAns;
@@ -233,13 +233,13 @@ const CommentView = ({ classroomName }) => {
>
- {postExists && (
+ {postExists && userRole.publish.comment && (
)}
- {postid === "newQorA" && }
+ {postid === "newQorA" && }
{/* {postid === "newPoll" && } */}
{postid === "newPoll" && }
{postExists &&
diff --git a/client/src/components/configPage/ConfigPanel.js b/client/src/components/configPage/ConfigPanel.js
index 8becbe86..a4c451b6 100644
--- a/client/src/components/configPage/ConfigPanel.js
+++ b/client/src/components/configPage/ConfigPanel.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useContext } from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
import Button from "../common/Button";
@@ -7,6 +7,7 @@ import RolePanel from "./roleConfigComponents/RolePanel";
import UserPanel from "./userConfigComponents/UserPanel";
import LazyFetch from "../common/requests/LazyFetch";
import LoadingDots from "../common/animation/LoadingDots";
+import { UserRoleContext } from "../context/UserRoleProvider";
const colorTest = [
"#dd0000",
@@ -48,14 +49,20 @@ const createRoleObject = (itemId) => {
// roleColor: colorTest[Math.floor(Math.random() * colorTest.length)],
permissions: {
publish: {
- postComment: false,
- reply: false,
+ question: false,
+ announcement: false,
poll: false,
+ general: false,
+ comment: false,
+ reply: false,
},
delete: {
- postComment: false,
- reply: false,
+ question: false,
+ announcement: false,
poll: false,
+ general: false,
+ comment: false,
+ reply: false,
},
participation: {
reactions: false,
@@ -63,9 +70,12 @@ const createRoleObject = (itemId) => {
pin: false,
},
edit: {
- postComment: false,
- reply: false,
+ question: false,
+ announcement: false,
poll: false,
+ general: false,
+ comment: false,
+ reply: false,
},
privacy: {
private: false,
@@ -74,7 +84,6 @@ const createRoleObject = (itemId) => {
admin: {
banUsers: false,
removeUsers: false,
- announce: false,
configure: false,
highlightName: false,
},
@@ -106,7 +115,13 @@ const GenerateRoleList = (roles, setRoles, userList, setUserList) => {
/**
* Generates a list of User Components for State Management
*/
-const GenerateUserList = (users, roles) => {
+const GenerateUserList = (
+ users,
+ roles,
+ displayDropdown,
+ displayBan,
+ displayRemove
+) => {
var userRole = { name: "null", roleColor: "#e7e7e7" };
return users.map((user, index) => {
@@ -123,12 +138,15 @@ const GenerateUserList = (users, roles) => {
userRole={userRole}
allRoles={roles}
unbanList={false}
+ displayDropdown={displayDropdown}
+ displayBan={displayBan}
+ displayRemove={displayRemove}
/>
);
});
};
-const GenerateBannedUserList = (blacklist) => {
+const GenerateBannedUserList = (blacklist, displayBan) => {
if (!blacklist) {
return <>>;
}
@@ -141,6 +159,7 @@ const GenerateBannedUserList = (blacklist) => {
userName={bannedUser.userName}
userImg={bannedUser.userImg}
unbanList={true}
+ displayBan={displayBan}
/>
);
});
@@ -155,6 +174,8 @@ const ConfigPanel = ({
setRoleIdCounter,
...props
}) => {
+ console.log("Course Roles: ", courseRoles);
+ const userRole = useContext(UserRoleContext);
const [loadingIcons, setLoadingIcons] = useState(true);
const [bannedUserList, setBannedUserList] = useState(null);
@@ -171,7 +192,9 @@ const ConfigPanel = ({
setDisplayBanned(true);
changeNumBanned(data.success.length);
}
- setBannedUserList(GenerateBannedUserList(data.success));
+ setBannedUserList(
+ GenerateBannedUserList(data.success, userRole.admin.banUsers)
+ );
},
onFailure: () => {
console.log(
@@ -186,9 +209,11 @@ const ConfigPanel = ({
let realUserList = GenerateUserList(
courseUsers,
courseRoles,
- numBannedUsers,
- changeNumBanned
+ userRole.admin.configure,
+ userRole.admin.banUsers,
+ userRole.admin.removeUsers
);
+ console.log("realUserList:", realUserList);
const [userList, setUserList] = useState(realUserList);
// State for roles ------------------------------------------------------
@@ -208,83 +233,90 @@ const ConfigPanel = ({
return (
-
- {loadingIcons ? (
-
-
-
- ) : (
- realRoleList
- )}
-
+ )}
+ {userRole.admin.configure && (
+
+ {
+ console.log("CourseRoles (Confirm): ", courseRoles);
+ let testList = [];
- for (let i = 0; i < realRoleList.length; i++) {
- console.log(realRoleList[i].props.roleObject);
- testList.push(realRoleList[i].props.roleObject);
- }
+ for (let i = 0; i < realRoleList.length; i++) {
+ console.log(realRoleList[i].props.roleObject);
+ testList.push(realRoleList[i].props.roleObject);
+ }
+
+ // alert("Feature is work in progress.");
+ LazyFetch({
+ type: "put",
+ endpoint: "/courses/" + courseId + "/roles",
+ data: {
+ roles: testList,
+ },
+ onSuccess: (data) => {
+ console.log("Success PUT Roles: ", data);
+ alert("Changes saved successfully.");
+ },
+ onFailure: (err) => {
+ console.log("Failed PUT Roles. ", err?.response);
+ alert("Error: Changes not saved. Please try again.");
+ },
+ });
+ }}
+ >
+ Confirm
+
+
+ )}
- // alert("Feature is work in progress.");
- LazyFetch({
- type: "put",
- endpoint: "/courses/" + courseId + "/roles",
- data: {
- roles: testList,
- },
- onSuccess: (data) => {
- console.log("Success PUT Roles: ", data);
- alert("Changes saved successfully.");
- },
- onFailure: (err) => {
- console.log("Failed PUT Roles. ", err?.response);
- alert("Error: Changes not saved. Please try again.");
- },
- });
- }}
- >
- Confirm
-
-
diff --git a/client/src/components/configPage/ConfigView.js b/client/src/components/configPage/ConfigView.js
index 425b0960..e387fa48 100644
--- a/client/src/components/configPage/ConfigView.js
+++ b/client/src/components/configPage/ConfigView.js
@@ -150,7 +150,13 @@ const ConfigView = ({ props }) => {
// ------------------------------------------------------------
var userIsAdmin = false;
- if (userRole) userIsAdmin = userRole.admin.configure;
+ var userCanBan = false;
+ var userCanRemove = false;
+ if (userRole) {
+ userIsAdmin = userRole.admin.configure;
+ userCanBan = userRole.admin.banUsers;
+ userCanRemove = userRole.admin.removeUsers;
+ }
/**
* Redirects the user to the landing page
@@ -172,7 +178,7 @@ const ConfigView = ({ props }) => {
{/* */}
- {userIsAdmin ? (
+ {userIsAdmin || userCanBan || userCanRemove ? (
{
)}
- {userIsAdmin ? (
+ {userIsAdmin || userCanBan || userCanRemove ? (
{
<>>
)}
- {userIsAdmin ? (
+ {userIsAdmin || userCanBan || userCanRemove ? (
//
{
+ if (e.key == "Enter") {
+ if (!nameFieldState) {
+ if (nameField.trim() == "") setNameField(roleName);
+ }
+ if (e.target.value != roleObject.name) {
+ roleObject.name = e.target.value;
+ }
+ setNameField(e.target.value);
+ setNameFieldState(true);
+ }
+ };
+
// console.log("This role id: ", props.value);
return (
@@ -119,13 +140,7 @@ const RolePanel = ({
{
- // console.log(e.target.value);
- if (e.target.value != roleObject.name) {
- roleObject.name = e.target.value;
- }
- setNameField(e.target.value);
- }}
+ onKeyDown={handleKeyDown}
>
{nameField}
@@ -135,6 +150,9 @@ const RolePanel = ({
primary
buttonColor={"rgba(0, 0, 0, 0.0)"}
onClick={() => {
+ if (nameFieldState) {
+ if (nameField.trim() == "") setNameField(roleName);
+ }
setNameFieldState(!nameFieldState);
}}
>
@@ -150,30 +168,30 @@ const RolePanel = ({
name: "Publish",
items: [
{
- stateLabel: "postComment",
- itemLabel: "Draft Posts / Comments",
+ stateLabel: "question",
+ itemLabel: "Users in this role can publish Questions",
changeRoleVal: (val) => {
- roleObject.permissions.publish.postComment = val;
+ roleObject.permissions.publish.question = val;
setPublishCheckedState({
...publishCheckedState,
- postComment: val,
+ question: val,
});
},
},
{
- stateLabel: "reply",
- itemLabel: "Draft Replies",
+ stateLabel: "announcement",
+ itemLabel: "Users in this role can publish Announcements",
changeRoleVal: (val) => {
- roleObject.permissions.publish.reply = val;
+ roleObject.permissions.publish.announcement = val;
setPublishCheckedState({
...publishCheckedState,
- reply: val,
+ announcement: val,
});
},
},
{
stateLabel: "poll",
- itemLabel: "Draft Polls",
+ itemLabel: "Users in this role can publish Polls",
changeRoleVal: (val) => {
roleObject.permissions.publish.poll = val;
setPublishCheckedState({
@@ -182,6 +200,39 @@ const RolePanel = ({
});
},
},
+ {
+ stateLabel: "general",
+ itemLabel: "Users in this role can publish General Posts",
+ changeRoleVal: (val) => {
+ roleObject.permissions.publish.general = val;
+ setPublishCheckedState({
+ ...publishCheckedState,
+ general: val,
+ });
+ },
+ },
+ {
+ stateLabel: "comment",
+ itemLabel: "Users in this role can publish comments on posts",
+ changeRoleVal: (val) => {
+ roleObject.permissions.publish.comment = val;
+ setPublishCheckedState({
+ ...publishCheckedState,
+ comment: val,
+ });
+ },
+ },
+ {
+ stateLabel: "reply",
+ itemLabel: "Users in this role can reply to comments",
+ changeRoleVal: (val) => {
+ roleObject.permissions.publish.reply = val;
+ setPublishCheckedState({
+ ...publishCheckedState,
+ reply: val,
+ });
+ },
+ },
],
}}
>
@@ -194,30 +245,31 @@ const RolePanel = ({
name: "Delete",
items: [
{
- stateLabel: "postComment",
- itemLabel: "Delete Posts / Comments",
+ stateLabel: "question",
+ itemLabel: "Users in this role can delete questions they made",
changeRoleVal: (val) => {
- roleObject.permissions.delete.postComment = val;
+ roleObject.permissions.delete.question = val;
setDeleteCheckedState({
...deleteCheckedState,
- postComment: val,
+ question: val,
});
},
},
{
- stateLabel: "reply",
- itemLabel: "Delete Replies",
+ stateLabel: "announcement",
+ itemLabel:
+ "Users in this role can delete announcements they made",
changeRoleVal: (val) => {
- roleObject.permissions.delete.reply = val;
+ roleObject.permissions.delete.announcement = val;
setDeleteCheckedState({
...deleteCheckedState,
- reply: val,
+ announcement: val,
});
},
},
{
stateLabel: "poll",
- itemLabel: "Delete Polls",
+ itemLabel: "Users in this role can delete polls they made",
changeRoleVal: (val) => {
roleObject.permissions.delete.poll = val;
setDeleteCheckedState({
@@ -226,6 +278,40 @@ const RolePanel = ({
});
},
},
+ {
+ stateLabel: "general",
+ itemLabel:
+ "Users in this role can delete general posts they made",
+ changeRoleVal: (val) => {
+ roleObject.permissions.delete.general = val;
+ setDeleteCheckedState({
+ ...deleteCheckedState,
+ general: val,
+ });
+ },
+ },
+ {
+ stateLabel: "comment",
+ itemLabel: "Users in this role can delete comments they made",
+ changeRoleVal: (val) => {
+ roleObject.permissions.delete.comment = val;
+ setDeleteCheckedState({
+ ...deleteCheckedState,
+ comment: val,
+ });
+ },
+ },
+ {
+ stateLabel: "reply",
+ itemLabel: "Users in this role can delete replies they made",
+ changeRoleVal: (val) => {
+ roleObject.permissions.delete.reply = val;
+ setDeleteCheckedState({
+ ...deleteCheckedState,
+ reply: val,
+ });
+ },
+ },
],
}}
>
@@ -238,30 +324,31 @@ const RolePanel = ({
name: "Edit",
items: [
{
- stateLabel: "postComment",
- itemLabel: "Edit Posts / Comments",
+ stateLabel: "question",
+ itemLabel: "Users in this role can edit questions that they made",
changeRoleVal: (val) => {
- roleObject.permissions.edit.postComment = val;
+ roleObject.permissions.edit.question = val;
setEditCheckedState({
...editCheckedState,
- postComment: val,
+ question: val,
});
},
},
{
- stateLabel: "reply",
- itemLabel: "Edit Replies",
+ stateLabel: "announcement",
+ itemLabel:
+ "Users in this role can edit announcements that they made",
changeRoleVal: (val) => {
- roleObject.permissions.edit.reply = val;
+ roleObject.permissions.edit.announcement = val;
setEditCheckedState({
...editCheckedState,
- reply: val,
+ announcement: val,
});
},
},
{
stateLabel: "poll",
- itemLabel: "Edit Polls",
+ itemLabel: "Users in this roll can edit polls that they made",
changeRoleVal: (val) => {
roleObject.permissions.edit.poll = val;
setEditCheckedState({
@@ -270,6 +357,40 @@ const RolePanel = ({
});
},
},
+ {
+ stateLabel: "general",
+ itemLabel:
+ "Users in this role can edit general posts that they made",
+ changeRoleVal: (val) => {
+ roleObject.permissions.edit.general = val;
+ setEditCheckedState({
+ ...editCheckedState,
+ general: val,
+ });
+ },
+ },
+ {
+ stateLabel: "comment",
+ itemLabel: "Users in this role can edit comments that they made",
+ changeRoleVal: (val) => {
+ roleObject.permissions.edit.comment = val;
+ setEditCheckedState({
+ ...editCheckedState,
+ comment: val,
+ });
+ },
+ },
+ {
+ stateLabel: "reply",
+ itemLabel: "Users in this role can edit replies that they made",
+ changeRoleVal: (val) => {
+ roleObject.permissions.edit.reply = val;
+ setEditCheckedState({
+ ...editCheckedState,
+ reply: val,
+ });
+ },
+ },
],
}}
>
@@ -283,7 +404,8 @@ const RolePanel = ({
items: [
{
stateLabel: "reactions",
- itemLabel: "React to Posts",
+ itemLabel:
+ "Users in this role can react to all posts, comments, and replies",
changeRoleVal: (val) => {
roleObject.permissions.participation.reactions = val;
setParticipationCheckedState({
@@ -294,7 +416,7 @@ const RolePanel = ({
},
{
stateLabel: "voteInPoll",
- itemLabel: "Vote in Polls",
+ itemLabel: "Users in this role can vote in all polls",
changeRoleVal: (val) => {
roleObject.permissions.participation.voteInPoll = val;
setParticipationCheckedState({
@@ -305,7 +427,7 @@ const RolePanel = ({
},
{
stateLabel: "pin",
- itemLabel: "Pin Posts",
+ itemLabel: "Users in this role can can pin all types of posts",
changeRoleVal: (val) => {
roleObject.permissions.participation.pin = val;
setParticipationCheckedState({
@@ -327,7 +449,8 @@ const RolePanel = ({
items: [
{
stateLabel: "private",
- itemLabel: "View Private Posts",
+ itemLabel:
+ "Users in this role can view all posts marked as private",
changeRoleVal: (val) => {
roleObject.permissions.privacy.private = val;
setPrivacyCheckedState({
@@ -338,7 +461,8 @@ const RolePanel = ({
},
{
stateLabel: "anonymous",
- itemLabel: "View Anonymous Posts",
+ itemLabel:
+ "Users in this role can draft anonymous posts of all types (general posts, questions, announcements, and polls), comments, and replies",
changeRoleVal: (val) => {
roleObject.permissions.privacy.anonymous = val;
setPrivacyCheckedState({
@@ -360,7 +484,8 @@ const RolePanel = ({
items: [
{
stateLabel: "banUsers",
- itemLabel: "Ban Users",
+ itemLabel:
+ "Users in this role can ban users in the course (does not include course creator)",
changeRoleVal: (val) => {
roleObject.permissions.admin.banUsers = val;
setAdminCheckedState({
@@ -371,7 +496,8 @@ const RolePanel = ({
},
{
stateLabel: "removeUsers",
- itemLabel: "Remove Users",
+ itemLabel:
+ "Users in this role can remove users in the course (does not include course creator)",
changeRoleVal: (val) => {
roleObject.permissions.admin.removeUsers = val;
setAdminCheckedState({
@@ -380,20 +506,10 @@ const RolePanel = ({
});
},
},
- {
- stateLabel: "announce",
- itemLabel: "Draft Announcements",
- changeRoleVal: (val) => {
- roleObject.permissions.admin.announce = val;
- setAdminCheckedState({
- ...adminCheckedState,
- announce: val,
- });
- },
- },
{
stateLabel: "configure",
- itemLabel: "Edit Course Configurations",
+ itemLabel:
+ "Users in this role can edit course configurations (this includes user roles and the ability to delete the course)",
changeRoleVal: (val) => {
roleObject.permissions.admin.configure = val;
setAdminCheckedState({
@@ -404,7 +520,8 @@ const RolePanel = ({
},
{
stateLabel: "highlightName",
- itemLabel: "Highlight Name",
+ itemLabel:
+ "Users in this role with this permission will have their name highlighted orange every time they create a post, comment, or reply",
changeRoleVal: (val) => {
roleObject.permissions.admin.highlightName = val;
setAdminCheckedState({
@@ -437,16 +554,16 @@ const RolePanel = ({
);
// let newRolesList = ;
let newRolesList = courseRoles.filter((role) => {
- console.log(
- "role._id: ",
- role._id,
- " , roleObject._id: ",
- roleObject._id
- );
+ // console.log(
+ // "role._id: ",
+ // role._id,
+ // " , roleObject._id: ",
+ // roleObject._id
+ // );
return role._id != roleObject._id;
});
- console.log("After Filter: ", newRolesList);
- setCourseRoles();
+ // console.log("After Filter: ", newRolesList);
+ setCourseRoles(newRolesList);
setUserList(GenerateUserList(userList, newRolesList));
},
diff --git a/client/src/components/configPage/userConfigComponents/UserPanel.js b/client/src/components/configPage/userConfigComponents/UserPanel.js
index c39edbfd..e4e37705 100644
--- a/client/src/components/configPage/userConfigComponents/UserPanel.js
+++ b/client/src/components/configPage/userConfigComponents/UserPanel.js
@@ -10,10 +10,7 @@ import Fetch from "../../common/requests/Fetch";
import Modal from "../../common/Modal";
import Errors from "../../common/Errors";
-// Hardcoded dummy values
-// Ultimately the goal is to pull these from the permissions object in the user context
const UserPerms = { canBan: true, canRemove: true };
-
/* Handle Role selection in the dropdown */
const GenerateRoleOptions = (roles, courseId, userId, setRoleName) => {
return roles.map((role) => ({
@@ -47,9 +44,19 @@ const UserPanel = ({
userId,
allRoles,
unbanList,
+ displayDropdown,
+ displayBan,
+ displayRemove,
...props
}) => {
const { courseId } = useParams();
+ // var UserPerms;
+ // if (userRole) {
+ // UserPerms = {
+ // canBan: userRole.permissions.admin.banUsers,
+ // canRemove: userRole.permissions.admin.removeUsers,
+ // };
+ // }
const name = userRole ? userRole.name : null;
@@ -143,7 +150,7 @@ const UserPanel = ({
{userName}
- {!isCourseCreator && !unbanList ? (
+ {displayDropdown && !isCourseCreator && !unbanList ? (
@@ -164,7 +171,7 @@ const UserPanel = ({
)}
- {UserPerms.canBan && !isCourseCreator && (
+ {displayBan && !isCourseCreator && (
)}
- {UserPerms.canRemove && !isCourseCreator && !unbanList && (
+ {displayRemove && !isCourseCreator && !unbanList && (
{
// console.log("User Object: ", user);
// console.log("OPTIONS User Role: ", userRole);
- // Will be used to conditionally render the config page button
+ // Will be used to conditionally render the config page button and draft post button
var userIsAdmin = false;
- if (userRole) userIsAdmin = userRole.admin.configure;
+ var userCanBan = false;
+ var userCanRemove = false;
+ var displayDraftPost = false;
+ var displayDraftPoll = false;
+ if (userRole) {
+ userIsAdmin = userRole.admin.configure;
+ userCanBan = userRole.admin.banUsers;
+ userCanRemove = userRole.admin.removeUsers;
+ displayDraftPost =
+ userRole.publish.question ||
+ userRole.publish.announcement ||
+ userRole.publish.general;
+ displayDraftPoll = userRole.publish.poll;
+ }
return (
OPTIONS
-
-
- Draft Post
-
-
-
-
- Draft Poll
-
-
+ {displayDraftPost && (
+
+
+ Draft Post
+
+
+ )}
+ {displayDraftPoll && (
+
+
+ Draft Poll
+
+
+ )}
{/* The Config page conditionally renders based on whether or not
the user has ADMIN priviledges for this course */}
- {userIsAdmin && (
+ {(userIsAdmin || userCanBan || userCanRemove) && (
{
var content;
if (
post.content.type === "question" ||
- post.content.type === "announcement"
+ post.content.type === "announcement" ||
+ post.content.type === "general"
) {
content = (
@@ -120,6 +121,9 @@ const PostView = ({ userRole, highlightedSection }) => {
case "Polls":
endpoint += "?filterby=poll";
break;
+ case "General Posts":
+ endpoint += "?filterby=general";
+ break;
default:
// Don't add a filter to endpoint
}
diff --git a/client/src/components/posts/Sidebar.js b/client/src/components/posts/Sidebar.js
index 7f56ecb7..6845e876 100644
--- a/client/src/components/posts/Sidebar.js
+++ b/client/src/components/posts/Sidebar.js
@@ -10,6 +10,7 @@ import HeartImg from "../../imgs/heart.svg";
import AnnouncementsImg from "../../imgs/announcements.svg";
import QuestionsImg from "../../imgs/questions.svg";
import PollsImg from "../../imgs/polls.svg";
+import GeneralImg from "../../imgs/general.svg";
/* Sidebar view shows tabs of different post feeds and shows which one is selected */
const Sidebar = ({ userRole, setHighlightedSection, highlightedSection }) => {
@@ -64,6 +65,12 @@ const Sidebar = ({ userRole, setHighlightedSection, highlightedSection }) => {
setHighlightedSection={setHighlightedSection}
highlightedSection={highlightedSection}
/>
+
{
return "#4a86fa";
case "Announcement":
return "#FA6A4A";
+ case "General":
+ return "#EDEDED";
default:
- return "#4a86fa";
+ return "#E7E7E7";
}
};
-const Draft = () => {
+const Draft = ({ userRole }) => {
const { courseId } = useParams();
const history = useHistory();
// State and handler for drafting posts
@@ -31,8 +33,19 @@ const Draft = () => {
isPrivate: false,
});
+ var defaultType;
+ if (userRole.publish.general) {
+ defaultType = "General";
+ } else if (userRole.publish.question) {
+ defaultType = "Question";
+ } else if (userRole.publish.announcement) {
+ defaultType = "Announcement";
+ } else {
+ // This should never happen
+ defaultType = "Unknown";
+ }
const [content, setContent] = useState({
- type: "Question",
+ type: defaultType,
raw: EditorState.createEmpty(),
plainText: EditorState.createEmpty(),
});
@@ -78,39 +91,71 @@ const Draft = () => {
});
};
- var titlePlaceholder = content.type ? content.type + " title" : "Post title";
+ // Styling Variables
+ var titlePlaceholder =
+ content.type != "Unknown" ? content.type + " title" : "Post title";
+ var displayQuestion;
+ var displayAnnouncement;
+ var displayGeneral;
+ if (userRole) {
+ displayQuestion = userRole.publish.question;
+ displayAnnouncement = userRole.publish.announcement;
+ displayGeneral = userRole.publish.general;
+ }
+ var accent = accentColor(content.type);
+
return (
-
+
-
- {
- setContent({ ...content, type: "Question" });
- }}
- style={{ margin: "0 .5em" }}
- >
- {
+ setContent({ ...content, type: "General" });
+ }}
+ style={{ margin: "0 1em" }}
>
- Question
-
-
- {
- setContent({ ...content, type: "Announcement" });
- }}
- style={{ margin: "0 2em" }}
- >
-
+ General
+
+
+ )}
+ {displayQuestion && (
+ {
+ setContent({ ...content, type: "Question" });
+ }}
+ style={{ margin: "0 1em" }}
+ >
+
+ Question
+
+
+ )}
+ {displayAnnouncement && (
+ {
+ setContent({ ...content, type: "Announcement" });
+ }}
+ style={{ margin: "0 1em" }}
>
- Announcement
-
-
+
+ Announcement
+
+
+ )}
(props.selected ? "#fff" : "#000")};
+ color: ${(props) =>
+ props.selected ? (props.isGeneral ? "#162B55" : "#ededed") : "#162B55"};
background-color: ${(props) =>
- props.selected ? props.accentColor : "#e7e7e7"};
+ props.selected
+ ? props.isGeneral
+ ? "#e7e7e7"
+ : props.accentColor
+ : "#e7e7e7"};
border-radius: 2px;
`;
diff --git a/client/src/components/posts/refactorComponents/PollWrapper.js b/client/src/components/posts/refactorComponents/PollWrapper.js
index 520e9a7e..b82bc03d 100644
--- a/client/src/components/posts/refactorComponents/PollWrapper.js
+++ b/client/src/components/posts/refactorComponents/PollWrapper.js
@@ -1,10 +1,12 @@
-import React, { useState } from "react";
+import React, { useContext, useState } from "react";
import Poll from "react-polls";
import { useParams } from "react-router";
import LazyFetch from "../../common/requests/LazyFetch";
+import { UserRoleContext } from "../../context/UserRoleProvider";
const PollWrapper = ({ post }) => {
const { courseId } = useParams();
+ const userRole = useContext(UserRoleContext);
// console.log("pollWrapper post: ", post);
const establishPollAns = (post) => {
@@ -25,18 +27,21 @@ const PollWrapper = ({ post }) => {
return answer;
});
- LazyFetch({
- type: "put",
- endpoint: "/courses/" + courseId + "/polls",
- data: { selectedOption: voteAnswer, postId: post._id },
- onSuccess: (data) => {
- // console.log("Data: ", data);
- setPollAns(newPollAnswers);
- },
- onFailure: (err) => {
- console.log("Err: ", err);
- },
- });
+ // Only send the request to the backend if the user has permission to do so
+ if (userRole.participation.voteInPoll) {
+ LazyFetch({
+ type: "put",
+ endpoint: "/courses/" + courseId + "/polls",
+ data: { selectedOption: voteAnswer, postId: post._id },
+ onSuccess: (data) => {
+ // console.log("Data: ", data);
+ setPollAns(newPollAnswers);
+ },
+ onFailure: (err) => {
+ console.log("Err: ", err);
+ },
+ });
+ }
};
// console.log("pollAns: ", pollAns);
@@ -46,7 +51,11 @@ const PollWrapper = ({ post }) => {
question={post.title}
answers={pollAns}
onVote={handleVote}
- vote={post.content.vote}
+ vote={
+ userRole && userRole.participation.voteInPoll
+ ? post.content.vote
+ : pollAns[0].option
+ }
noStorage
onClick={(event) => {
event.stopPropagation();
diff --git a/client/src/components/posts/refactorComponents/PostWrapper.js b/client/src/components/posts/refactorComponents/PostWrapper.js
index 4485bbea..0017a1df 100644
--- a/client/src/components/posts/refactorComponents/PostWrapper.js
+++ b/client/src/components/posts/refactorComponents/PostWrapper.js
@@ -22,6 +22,8 @@ const accentColor = (type) => {
return "#FA6A4A";
case "Poll":
return "#4CAF50";
+ case "General":
+ return "#ededed";
default:
return "#4a86fa";
}
@@ -96,21 +98,76 @@ const PostWrapper = ({
setIsEditing(true);
};
+ const generateEditDeleteOption = (optionType) => {
+ var resultingOption;
+ var role = optionType == "delete" ? userRole.delete : userRole.edit;
+ if (
+ postType == "Question" &&
+ role.question &&
+ (postObject.postedBy._id == user._id ||
+ postObject.postedBy._id == user.anonymousId)
+ ) {
+ resultingOption = {
+ onClick: () => {
+ optionType == "delete"
+ ? handleDelete(postObject._id, postObject.courseId)
+ : handleEdit();
+ },
+ label: optionType == "delete" ? "Delete question" : "Edit question",
+ };
+ } else if (
+ postType == "Announcement" &&
+ role.announcement &&
+ (postObject.postedBy._id == user._id ||
+ postObject.postedBy._id == user.anonymousId)
+ ) {
+ resultingOption = {
+ onClick: () => {
+ optionType == "delete"
+ ? handleDelete(postObject._id, postObject.courseId)
+ : handleEdit();
+ },
+ label:
+ optionType == "delete" ? "Delete announcement" : "Edit announcement",
+ };
+ } else if (
+ postType == "Poll" &&
+ role.poll &&
+ (postObject.postedBy._id == user._id ||
+ postObject.postedBy._id == user.anonymousId)
+ ) {
+ resultingOption = {
+ onClick: () => {
+ optionType == "delete"
+ ? handleDelete(postObject._id, postObject.courseId)
+ : handleEdit();
+ },
+ label: optionType == "delete" ? "Delete poll" : "Edit poll",
+ };
+ } else if (
+ postType == "General" &&
+ role.general &&
+ (postObject.postedBy._id == user._id ||
+ postObject.postedBy._id == user.anonymousId)
+ ) {
+ resultingOption = {
+ onClick: () => {
+ optionType == "delete"
+ ? handleDelete(postObject._id, postObject.courseId)
+ : handleEdit();
+ },
+ label: optionType == "delete" ? "Delete post" : "Edit post",
+ };
+ } else {
+ resultingOption = null;
+ }
+ return resultingOption;
+ };
+
const generateDropdownOptions = () => {
if (userRole) {
- let deleteOption =
- userRole.delete.postComment && postObject.postedBy._id == user._id
- ? {
- onClick: () => {
- handleDelete(postObject._id, postObject.courseId);
- },
- label: "Delete post",
- }
- : null;
- let editOption =
- userRole.edit.postComment && postObject.postedBy._id == user._id
- ? { onClick: handleEdit, label: "Edit post" }
- : null;
+ let deleteOption = generateEditDeleteOption("delete");
+ let editOption = generateEditDeleteOption("edit");
let pinOption = userRole.participation.pin
? {
onClick: () => {
@@ -159,9 +216,13 @@ const PostWrapper = ({
isRead={postObject.read}
accentColor={accentColor(postType)}
/>
-
- {postType ? postType : "Question"}
-
+ {postType != "General" ? (
+
+ {postType ? postType : "Question"}
+
+ ) : (
+ <>>
+ )}
{postObject.title ? postObject.title : "Error getting post title"}
@@ -194,7 +255,9 @@ const PostWrapper = ({
}}
postType={postType}
>
- {postType == "Question" || postType == "Announcement"
+ {postType == "Question" ||
+ postType == "Announcement" ||
+ postType == "General"
? React.cloneElement(content, { edit: { isEditing, setIsEditing } })
: content}
@@ -212,12 +275,15 @@ const PostWrapper = ({
Posted by {postObject.postedBy.first} {postObject.postedBy.last}
-
+ {userRole && userRole.participation.reactions && (
+
+ )}
+
+
+
+
+
+
+
diff --git a/server/README-server.md b/server/README-server.md
index 7e67c4bf..14c340df 100644
--- a/server/README-server.md
+++ b/server/README-server.md
@@ -244,7 +244,7 @@ This component handles setting up all of our MongoDB models so that each collect
]
```
-### Roles Model (NEW 04.18.21)
+### Roles Model (OLD)
```json
{
@@ -286,6 +286,56 @@ This component handles setting up all of our MongoDB models so that each collect
}
```
+### Roles Model (NEW 07.15.21)
+
+```json
+{
+ "_id": "role id goes here",
+ "name": "the name of the role goes here",
+ "permissions": {
+ "publish": {
+ "question": true,
+ "announcement": true,
+ "poll": true,
+ "general": true,
+ "comment": true,
+ "reply": true
+ },
+ "delete": {
+ "question": true,
+ "announcement": true,
+ "poll": true,
+ "general": true,
+ "comment": true,
+ "reply": true
+ },
+ "participation": {
+ "reactions": true,
+ "voteInPoll": true,
+ "pin": true
+ },
+ "edit": {
+ "question": true,
+ "announcement": true,
+ "poll": true,
+ "general": true,
+ "comment": true,
+ "reply": true
+ },
+ "privacy": {
+ "private": true,
+ "anonymous": true
+ },
+ "admin": {
+ "banUsers": true,
+ "removeUsers": true,
+ "configure": true,
+ "highlightName": true
+ }
+ }
+}
+```
+
### Deprecated Models
#### Old User Model
diff --git a/server/inquire/auth.py b/server/inquire/auth.py
index f2a4e4b7..01b68399 100644
--- a/server/inquire/auth.py
+++ b/server/inquire/auth.py
@@ -63,7 +63,6 @@ def get_current_user():
if role:
user.permissions = role.permissions
g.current_user = user
-
return g.current_user
@@ -90,11 +89,12 @@ def _deep_access(d, keys):
return None
return d
+
def _permission_comparison(user_permissions: dict, required_permissions: list):
"""
Checks if the values in the user_permissions dict are true for the keys specified in the required_permissions list.
For nested values specify keys in the following format "level1key-level2key-level3key".
-
+
Required_permissions can contain a subset of permissions to check.
Example: _permission_comparison({"a":True, b:False, c:{d:True, e:True}}, ["a", "c-e"]) == True
@@ -133,9 +133,11 @@ def wrapper(*args, **kwargs):
if not current_user.permissions:
missing_permissions = required_permissions
else:
- missing_permissions = _permission_comparison(current_user.permissions, required_permissions)
+ missing_permissions = _permission_comparison(
+ current_user.permissions, required_permissions)
if missing_permissions:
- abort(401, errors=[f'Resource access restricted: missing course permission(s) {", ".join(missing_permissions)}'])
+ abort(401, errors=[
+ f'Resource access restricted: missing course permission(s) {", ".join(missing_permissions)}'])
return func(*args, **kwargs)
return wrapper
return actual_decorator
@@ -227,6 +229,7 @@ def retrieve_user(_id):
else:
return None
+
def retrieve_role(_id):
'''Retrieves the role object from the database'''
query = Role.objects.raw({'_id': _id})
@@ -240,7 +243,6 @@ def retrieve_role(_id):
return None
-
def create_user(data, mode="google"):
if mode == "google":
user = User(_id=data['sub'], first=data['given_name'], last=data['family_name'],
diff --git a/server/inquire/mongo.py b/server/inquire/mongo.py
index 18b24949..835b927e 100644
--- a/server/inquire/mongo.py
+++ b/server/inquire/mongo.py
@@ -31,6 +31,8 @@ def post_content_validator(content):
return True
elif post_type == "announcement":
return True
+ elif post_type == "general":
+ return True
else:
raise ValidationError("Post type not recognized")
diff --git a/server/inquire/resources/ban_remove.py b/server/inquire/resources/ban_remove.py
index d8ef48b7..a67de20c 100644
--- a/server/inquire/resources/ban_remove.py
+++ b/server/inquire/resources/ban_remove.py
@@ -9,13 +9,14 @@
class BanRemove(Resource):
- @permission_layer(required_permissions=["admin-configure"])
def put(self, courseId):
+ if not current_user.permissions['admin']['banUsers'] and not current_user.permissions['admin']['removeUsers']:
+ return {"errors": ["You do not have permission to ban or remove users from the course."]}, 401
+
parser = reqparse.RequestParser()
parser.add_argument('type')
parser.add_argument('userId')
args = parser.parse_args()
- print("userId:", args['userId'])
# Validate course exists and store it in course variable
try:
@@ -42,10 +43,14 @@ def put(self, courseId):
filler = ""
if args['type'] == "remove":
+ if not current_user.permissions['admin']['removeUsers']:
+ return {"errors": ["You do not have permission to remove users in this course"]}, 401
# Removing students
self.remove_user(user, course)
filler = "removed"
elif args['type'] == "ban":
+ if not current_user.permissions['admin']['banUsers']:
+ return {"errors": ["You do not have permission to ban users in this course"]}, 401
# Banning students
if args['userId'] not in course.blacklist:
# Add the banned user to the blacklist
diff --git a/server/inquire/resources/comments.py b/server/inquire/resources/comments.py
index b73a0655..0a9b1576 100644
--- a/server/inquire/resources/comments.py
+++ b/server/inquire/resources/comments.py
@@ -53,7 +53,7 @@ def get(self, courseId=None, postId=None):
return [self.serialize(comment) for comment in Comment.objects.raw({'postId': postId})]
- @permission_layer(required_permissions=["publish-postComment"])
+ @permission_layer(required_permissions=["publish-comment"])
def post(self, courseId=None, postId=None):
"""
Creates a new comment
@@ -99,6 +99,7 @@ def post(self, courseId=None, postId=None):
# Adding user info to dict
anonymous = args['isAnonymous']
if anonymous:
+ highlighted = False
postedBy = {"first": "Anonymous", "last": "",
"_id": current_user.anonymousId, "anonymous": anonymous}
else:
@@ -121,7 +122,7 @@ def post(self, courseId=None, postId=None):
current_app.socketio.emit('Comment/create', result, room=postId)
return result, 200
- @permission_layer(required_permissions=["edit-postComment"])
+ @permission_layer(required_permissions=["edit-comment"])
def put(self, courseId=None, postId=None):
"""
Updates a comment
@@ -181,7 +182,7 @@ def put(self, courseId=None, postId=None):
result = self.serialize(comment)
return result, 200
- @permission_layer(required_permissions=["delete-postComment"])
+ @permission_layer(required_permissions=["delete-comment"])
def delete(self, courseId=None, postId=None):
"""
Deletes a comment
diff --git a/server/inquire/resources/posts.py b/server/inquire/resources/posts.py
index 1cfdde99..b492bb2a 100644
--- a/server/inquire/resources/posts.py
+++ b/server/inquire/resources/posts.py
@@ -19,7 +19,7 @@
class Posts(Resource):
- @permission_layer(required_permissions=["publish-postComment"], require_joined_course=True)
+ @permission_layer(require_joined_course=True)
def post(self, courseId=None):
"""
Creates a new post
@@ -51,6 +51,11 @@ def post(self, courseId=None):
schema:
$ref: '#/definitions/403Response'
"""
+ # Make sure the current user at least has one permission to post
+ # print("User Perms: ", current_user.permissions)
+ if not current_user.permissions['publish']['question'] and not current_user.permissions['publish']['announcement'] and not current_user.permissions['publish']['poll'] and not current_user.permissions['publish']['general']:
+ return {"errors": ["You do not have permission to make any post in this course."]}, 401
+
# Parse arguments
parser = reqparse.RequestParser()
parser.add_argument('title')
@@ -59,6 +64,11 @@ def post(self, courseId=None):
parser.add_argument('isAnonymous', type=bool)
args = parser.parse_args()
+ # Check that the user has permission to make the type of post they wish to make
+ permission_errs = self.check_permissions("publish", args)
+ if (bool(permission_errs)):
+ return {"errors": permission_errs}, 401
+
# How polls look being sent from frontend
# {
# "type": "blah",
@@ -76,7 +86,9 @@ def post(self, courseId=None):
# Adding user info to dict
anonymous = args['isAnonymous']
+
if anonymous:
+ highlighted = False
postedBy = {"first": "Anonymous", "last": "",
"_id": current_user.anonymousId, "anonymous": anonymous}
else:
@@ -217,6 +229,16 @@ def get(self, courseId=None):
query = Post.objects.raw(queryParams).order_by(
[("isPinned", -1), ("createdDate", sort_date)])
+ # Filter by 'general'
+ elif filterby == 'general':
+ # Check if the user can see private posts
+ if not user_perms["privacy"]["private"]:
+ queryParams['$or'] = [{'isPrivate': False}, {'postedBy._id': {
+ '$in': [current_user._id, current_user.anonymousId]}}]
+ queryParams["content.type"] = "general"
+ query = Post.objects.raw(queryParams).order_by(
+ [("isPinned", -1), ("createdDate", sort_date)])
+
# If the current user can see private posts and there's no search
elif user_perms["privacy"]["private"] and (req is None):
query = Post.objects.raw(
@@ -250,7 +272,6 @@ def get(self, courseId=None):
return result, 200
- @permission_layer(required_permissions=["delete-postComment"])
def delete(self, courseId=None):
"""
Deletes a post
@@ -297,6 +318,10 @@ def delete(self, courseId=None):
description: Whether or not the post was deleted
example: false
"""
+ # Make sure the current user at least has one permission to delete
+ if not current_user.permissions['delete']['question'] and not current_user.permissions['delete']['announcement'] and not current_user.permissions['delete']['poll'] and not current_user.permissions['delete']['general']:
+ return {"errors": ["You do not have permission to delete any type of post in this course."]}, 401
+
# Parse arguments
parser = reqparse.RequestParser()
parser.add_argument('_id')
@@ -310,6 +335,11 @@ def delete(self, courseId=None):
except Post.MultipleObjectsReturned:
return {'deleted': False, 'errors': f"Duplicate post detected, multiple posts in database with id {args['_id']}"}, 400
+ # Make sure the user has permission to delete the type of post they want to delete
+ permission_errs = self.check_permissions("delete", post)
+ if (bool(permission_errs)):
+ return {"errors": permission_errs}, 401
+
# Permission check
# FIX ME: Switch to using something other than "admin-configure" as the admin permission for deleting posts
if current_user._id == post.postedBy['_id'] or current_user.anonymousId == post.postedBy['_id'] or current_user.permissions["admin"]["configure"]:
@@ -326,7 +356,6 @@ def delete(self, courseId=None):
else:
return {'deleted': False}, 403
- @permission_layer(required_permissions=["edit-postComment"])
def put(self, courseId=None):
"""
Edits a post
@@ -358,21 +387,27 @@ def put(self, courseId=None):
schema:
$ref: '#/definitions/403Response'
"""
+ # Make sure the current user at least has one permission to edit
+ if not current_user.permissions['edit']['question'] and not current_user.permissions['edit']['announcement'] and not current_user.permissions['edit']['poll'] and not current_user.permissions['edit']['general']:
+ return {"errors": ["You do not have permission to edit any type of post in this course."]}, 401
+
# Parse the request
parser = reqparse.RequestParser()
parser.add_argument('title')
parser.add_argument('content', type=dict)
parser.add_argument('_id')
args = parser.parse_args()
- print(args.content)
+
+ # Make sure the user has permission to edit the type of post they wish to edit
+ permission_errs = self.check_permissions("edit", args)
+ if (bool(permission_errs)):
+ return {"errors": permission_errs}, 401
# Validate the args
errors = self.validate_post(args)
if(bool(errors)):
return {"errors": errors}, 400
- # print("AFTER VALIDATION")
-
# Get the post you want to update
try:
post = Post.objects.get({'_id': args['_id']})
@@ -381,22 +416,17 @@ def put(self, courseId=None):
except Post.MultipleObjectsReturned:
return {'updated': False, 'errors': f"Duplicate post detected, multiple posts in database with id {args['_id']}"}, 400
- # print("AFTER DUPLICATE POST DETECTION TEST")
-
new_content_type = args["content"]["type"]
if new_content_type != post.content["type"]:
return {'updated': False, 'errors': f"Cannot change post type"}, 400
# if post.content["type"] == "poll":
# return {'updated': False, 'errors': f"Cannot modify polls"}, 400
- # print("AFTER CHANGE / MODIFY TEST")
-
id_match = current_user._id == post.postedBy[
'_id'] or current_user.anonymousId == post.postedBy['_id']
if not id_match:
return {'updated': False, 'errors': f"Cannot modify other users posts"}, 400
- # print("AFTER Other users test")
if post.content["type"] != "poll":
if post.title != args['title']:
post.title = args['title']
@@ -409,6 +439,23 @@ def put(self, courseId=None):
result = self.serialize(post)
return result, 200
+ def check_permissions(self, request_type, post_args):
+ # Check that the user has permission to do what they wish to do
+ errors = []
+ if (not current_user.permissions[request_type]['question']) and (post_args.content.get("type") == "question"):
+ errors.append(
+ f"You do not have permission to {request_type} questions in this course")
+ elif not current_user.permissions[request_type]['announcement'] and (post_args.content.get("type") == "announcement"):
+ errors.append(
+ f"You do not have permission to {request_type} announcements in this course")
+ elif not current_user.permissions[request_type]['poll'] and (post_args.content.get("type") == "poll"):
+ errors.append(
+ f"You do not have permission to {request_type} polls in this course")
+ elif not current_user.permissions[request_type]['general'] and (post_args.content.get("type") == "general"):
+ errors.append(
+ f"You do not have permission to {request_type} general posts in this course")
+ return errors
+
def validate_post(self, args):
errors = []
# Make sure title is provided
@@ -423,11 +470,11 @@ def validate_post(self, args):
errors.append("Please provide a type for the post")
return errors
# Validate the type. Types include question, announcement, and poll.
- if not (args.content["type"] == "question" or args.content["type"] == "announcement" or args.content["type"] == "poll"):
+ if not (args.content["type"] == "question" or args.content["type"] == "announcement" or args.content["type"] == "poll" or args.content["type"] == "general"):
errors.append(
- "Invalid type provided. Valid types are: question, announcement, or poll.")
+ "Invalid type provided. Valid types are: question, announcement, poll, or general.")
# Make sure text field is provided for questions and announcements
- if (args.content["type"] == "question" or args.content["type"] == "announcement"):
+ if (args.content["type"] == "question" or args.content["type"] == "announcement" or args.content['type'] == "general"):
raw = args.content.get("raw")
plaintext = args.content.get("plainText")
if not (raw and plaintext and type(raw) == dict and type(plaintext) == str):
diff --git a/server/inquire/resources/replies.py b/server/inquire/resources/replies.py
index a426aa60..330ae033 100644
--- a/server/inquire/resources/replies.py
+++ b/server/inquire/resources/replies.py
@@ -65,6 +65,7 @@ def post(self, courseId=None, postId=None, comment_id=None):
# Adding user info to dict
anonymous = args['isAnonymous']
if anonymous:
+ highlighted = False
postedBy = {"first": "Anonymous", "last": "",
"_id": current_user.anonymousId, "anonymous": anonymous}
else:
diff --git a/server/inquire/resources/roles.py b/server/inquire/resources/roles.py
index 73771240..96659928 100644
--- a/server/inquire/resources/roles.py
+++ b/server/inquire/resources/roles.py
@@ -9,8 +9,10 @@
class Roles(Resource):
- @permission_layer(required_permissions=["admin-configure"])
def get(self, courseId):
+ if not current_user.permissions['admin']['configure'] and not current_user.permissions['admin']['banUsers'] and not current_user.permissions['admin']['removeUsers']:
+ return {"errors": ["You do not have permission to view the course configuration page."]}, 401
+
try:
course = Course.objects.get({"_id": courseId})
except Course.DoesNotExist:
@@ -114,14 +116,13 @@ def delete(self, courseId):
try:
role = Role.objects.get({"_id": roleId})
role.delete()
- course.roles.pop(roleId,None)
+ course.roles.pop(roleId, None)
course.save()
return {"deleted": True}
except Role.DoesNotExist:
return {"deleted": False, "error": f"Role with id {str(roleId)} does not exit"}
except Exception:
return {"deleted": False, "error": "Unspecified error occured"}
-
def _serialize(self, role):
j = role.to_son()
diff --git a/server/inquire/roles/admin.py b/server/inquire/roles/admin.py
index 87f88df7..7738e0c7 100644
--- a/server/inquire/roles/admin.py
+++ b/server/inquire/roles/admin.py
@@ -1,13 +1,19 @@
admin = {
"publish": {
- "postComment": True,
- "reply": True,
- "poll": True
+ "question": True,
+ "announcement": True,
+ "poll": True,
+ "general": True,
+ "comment": True,
+ "reply": True
},
"delete": {
- "postComment": True,
- "reply": True,
- "poll": True
+ "question": True,
+ "announcement": True,
+ "poll": True,
+ "general": True,
+ "comment": True,
+ "reply": True
},
"participation": {
"reactions": True,
@@ -15,18 +21,22 @@
"pin": True
},
"edit": {
- "postComment": True,
- "reply": True,
- "poll": True
+ "question": True,
+ "announcement": False,
+ "poll": True,
+ "general": True,
+ "comment": True,
+ "reply": True
},
"privacy": {
"private": True,
+ # Change to anonymous posts/anonymous comments/replies
"anonymous": True
},
"admin": {
"banUsers": True,
"removeUsers": True,
- "announce": True,
+ # "deleteOther": False,
"configure": True,
"highlightName": True
}
diff --git a/server/inquire/roles/student.py b/server/inquire/roles/student.py
index a962ad57..2a2b8ea9 100644
--- a/server/inquire/roles/student.py
+++ b/server/inquire/roles/student.py
@@ -1,13 +1,19 @@
student = {
"publish": {
- "postComment": True,
- "reply": True,
- "poll": False
+ "question": True,
+ "announcement": True,
+ "poll": False,
+ "general": True,
+ "comment": True,
+ "reply": True
},
"delete": {
- "postComment": True,
- "reply": True,
- "poll": False
+ "question": True,
+ "announcement": True,
+ "poll": False,
+ "general": True,
+ "comment": True,
+ "reply": True
},
"participation": {
"reactions": True,
@@ -15,9 +21,12 @@
"pin": False
},
"edit": {
- "postComment": True,
- "reply": True,
- "poll": True
+ "question": True,
+ "announcement": True,
+ "poll": False,
+ "general": True,
+ "comment": True,
+ "reply": True
},
"privacy": {
"private": False,
@@ -26,7 +35,7 @@
"admin": {
"banUsers": False,
"removeUsers": False,
- "announce": False,
+ # "deleteOther": False,
"configure": False,
"highlightName": False
}