Skip to content

Commit

Permalink
Merge pull request #1492 from clpetersonucf/react/fixes-and-polish-pa…
Browse files Browse the repository at this point in the history
…rt-five

[React branch] Fixes and polish part five
  • Loading branch information
clpetersonucf authored Sep 21, 2023
2 parents fd51500 + b2c274c commit 1d8ffbf
Show file tree
Hide file tree
Showing 39 changed files with 1,311 additions and 822 deletions.
54 changes: 54 additions & 0 deletions fuel/app/classes/controller/api/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,58 @@ public function post_settings()

return $this->response($reply);
}

public function post_roles()
{
if (\Service_User::verify_session() !== true) return $this->response('Not logged in', 401);
// this endpoint is only available to superusers!
if ( ! \Materia\Perm_Manager::is_super_user()) return $this->response('Not authorized', 403);

$success = false;
$user_id = Input::json('id', null);
$roles = [
'basic_author' => Input::json('author', false),
'support_user' => Input::json('support_user', false)
];

if ( ! $user_id) return $this->response('User ID not provided', 401);

$current_roles = \Materia\Perm_Manager::get_user_roles($user_id);
$current_roles_condensed = array_map( fn($r) => $r->name, $current_roles);

$roles_to_add = [];
$roles_to_revoke = [];

foreach ($roles as $name => $val)
{
if ( ! in_array($name, $current_roles_condensed) && $val == true) array_push($roles_to_add, $name);
else if (in_array($name, $current_roles_condensed) && $val == false) array_push($roles_to_revoke, $name);
}

$message = '';

if (count($roles_to_add) > 0)
{
$success = \Materia\Perm_Manager::add_users_to_roles([$user_id], $roles_to_add);
if ($success != true) return $this->response(['success' => false, 'status' => 'Failed to add roles']);
$message .= count($roles_to_add).' role(s) added.';
}

if (count($roles_to_revoke) > 0)
{
$success = \Materia\Perm_Manager::remove_users_from_roles([$user_id], $roles_to_revoke);
if ($success != true) return $this->response(['success' => false, 'status' => 'Failed to revoke roles']);
$message .= count($roles_to_revoke).' role(s) revoked.';
}

if (strlen($message) == 0)
{
$message .= 'No roles were changed.';
}

return $this->response([
'success' => true,
'status' => $message
]);
}
}
2 changes: 2 additions & 0 deletions fuel/app/classes/controller/widgets.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ public function action_play_widget($inst_id = false)

public function action_play_embedded($inst_id = false)
{
// if routed from the legacy LTI URL, the instance id is available as a GET parameter
if ( ! $inst_id && \Input::get('widget') ) $inst_id = \Input::get('widget');
// context_id isolates attempt count for an class so a user's attempt limit is reset per course
Session::set('context_id', \Input::post('context_id'));
return $this->_play_widget($inst_id, false, true);
Expand Down
3 changes: 1 addition & 2 deletions fuel/app/classes/materia/perm/manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,11 @@ static public function get_user_roles($user_id = 0)
->as_object();

$current_id = \Model_User::find_current_id();
$roles = [];

// return logged in user's roles if id is 0 or less, non su users can only use this method
if ($user_id <= 0 || $user_id == $current_id)
{
$roles = [];

$results = $q->where('m.user_id', $current_id)
->execute();

Expand Down
10 changes: 5 additions & 5 deletions fuel/app/classes/model/notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,23 @@ public static function send_item_notification(int $from_user_id, int $to_user_id
switch ($mode)
{
case 'disabled':
$subject = "<b>$user_link is no longer sharing \"$widget_name\" with you.</b>";
$subject = "$user_link is no longer sharing \"$widget_name\" with you.";
break;

case 'changed':
$subject = "<b>$user_link changed your access to widget \"$widget_link\".</b><br/> You now have $perm_string access.";
$subject = "$user_link changed your access to widget \"$widget_link\".<br/> You now have $perm_string access.";
break;

case 'expired':
$subject = "<b>Your access to \"$widget_name\" has automatically expired.</b>";
$subject = "Your access to \"$widget_name\" has automatically expired.";
break;

case 'deleted':
$subject = "<b>$user_link deleted $widget_type widget \"$widget_name\".</b>";
$subject = "$user_link deleted $widget_type widget \"$widget_name\".";
break;

case 'access_request':
$subject = "<b>$user_link is requesting access to your widget \"$widget_name\".</b><br /> The widget is currently being used within a course in your LMS.";
$subject = "$user_link is requesting access to your widget \"$widget_name\".<br /> The widget is currently being used within a course in your LMS.";
$action = 'access_request';
break;

Expand Down
1 change: 1 addition & 0 deletions fuel/app/classes/model/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public function to_array($custom = false, $recurse = false, $eav = false)
$array['avatar'] = $avatar;
$array['is_student'] = \Materia\Perm_Manager::is_student($this->id);
$array['is_support_user'] = \Materia\Perm_Manager::does_user_have_role([\Materia\Perm_Role::SUPPORT], $this->id);
if (\Materia\Perm_Manager::does_user_have_role([\Materia\Perm_Role::SU], $this->id)) $array['is_super_user'] = true;
return $array;
}

Expand Down
Binary file modified public/img/front1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/img/front2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/img/front3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/retina/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/retina/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/retina/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions src/components/catalog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ const Catalog = ({widgets = [], isLoading = true}) => {
const [filteredWidgets, isFiltered] = useMemo(() => {
let isFiltered = false

// widgets with the in_catalog flag set to false should not be included by default
// in_catalog widgets are already being rendered via featured widgets
// append remaining widgets that are playable but not in_catalog
let results = widgets.filter(w => {
return parseInt(w.in_catalog)
return parseInt(w.is_playable) == 1 && parseInt(w.in_catalog) == 0
})
// filters are active, only match active filters
if(state.activeFilters.length){
Expand Down
2 changes: 1 addition & 1 deletion src/components/header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const Header = ({
// Not being used
profileMenuRender = (
<nav className={`profile-menu ${optionsOpen ? 'show' : ''}`}>
<span class="arrow-top"></span>
<span className="arrow-top"></span>
<ul>
<li>
<span>{`${user.first} ${user.last}`}</span>
Expand Down
8 changes: 4 additions & 4 deletions src/components/homepage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const Homepage = () => (
<section className='front_bottom'>
<section className='wrapper'>
<div className="wrapper_first">
<div>
<div className='wrapper_content'>
<h2>Create Quickly and Easily</h2>
<p className="front_bottom_desc">
Materia's design philosophy is to be incredibly easy to use.
Expand All @@ -55,18 +55,18 @@ const Homepage = () => (
<img src='/img/front2.png' alt='screen shot of creating a crossword widget'/>
</div>
<div className="wrapper_second">
<div>
<div className='wrapper_content'>
<h2>Engage Your Students</h2>
<p className="front_bottom_desc">
Re-imagine your course filled with diverse and interesting experiences.
It can bring life to content modules, practice, study activities, and even assessments.
Engage students with game mechanics like: story-telling, competition, instant feedback, and instant reward systems.
</p>
</div>
<img src='/img/front1.png' alt='screen shot of a labeling widget' />
<img src='/img/front1.png' alt='screen shot of a sort it out widget' />
</div>
<div className="wrapper_third">
<div>
<div className='wrapper_content'>
<h2>Integrate with Your Course</h2>
<p className="front_bottom_desc">
Materia integrates into Canvas seamlessly.
Expand Down
43 changes: 34 additions & 9 deletions src/components/homepage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
margin-right: 40px;
height: 400px;

p {
text-align: left;
}

h1 span.engage {
color: #0093e7;
}
Expand Down Expand Up @@ -108,6 +112,7 @@
padding-top: 65px;

.wrapper {
max-width: 1400px;
margin: 0 auto;
}
div {
Expand All @@ -120,26 +125,45 @@
text-align: center;
display: grid;

div.wrapper_content {
margin: 0 0 20px 0;
}

h2 {
margin-bottom: 6px;
font-size: 30px;
font-weight: 500;
color: #000;
border-bottom: dotted 1px #666;
}

&.wrapper_first, &.wrapper_second, &.wrapper_third {
margin: 0 10%;
margin: 0 10% 20px 10%;
justify-items: center;
}

&.wrapper_first, &.wrapper_third {
p {
margin-right: 25px;
}
}

&.wrapper_second {
p {
margin-left: 25px;
}
}

p {
font-size: 16px;
line-height: 150%;
}
}

img {
border: solid 2px #ffffff;
box-shadow: 1px 2px 4px #888;
max-width: 290px;
padding: 5px;
border: dotted 1px #666;
margin-top: 20px;
}
img:nth-of-type(2) {
Expand All @@ -155,21 +179,21 @@
}
.front_bottom {
div {
margin: 0px 110px 20px 50px !important;
text-align: left !important;
margin: 0 0 20px 0;
// margin: 0px 110px 20px 50px;
text-align: left;

&.wrapper_first, &.wrapper_second, &.wrapper_third {
display: inline-flex;
align-items: center;
}

&.wrapper_second {
margin: 0px 50px 20px 110px !important;
// margin: 0px 50px 20px 110px;
flex-direction: row-reverse;

div {
text-align: right !important;
margin-right: 50px !important;
text-align: right;
}

img {
Expand All @@ -180,8 +204,9 @@
}
}
.p_s {
max-width: 1400px;
text-align: center;
margin: 30px 40px;
margin: 30px 10%;

h2 {
font-size: 30px;
Expand Down
30 changes: 30 additions & 0 deletions src/components/hooks/useUpdateUserRoles.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useMutation, useQueryClient } from 'react-query'
import { apiUpdateUserRoles } from '../../util/api'

export default function useUpdateUserRoles() {

const queryClient = useQueryClient()

return useMutation(
apiUpdateUserRoles,
{
onMutate: async roles => {
await queryClient.cancelQueries('search-users')
const val = {...queryClient.getQueryData('search-users')}
const prior = queryClient.getQueryData('search-users')

queryClient.setQueryData('search-users', () => val)

return { prior }
},
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries('search-users')
variables.successFunc(data)
},
onError: (err, newRoles, context) => {
queryClient.setQueryData('search-users', context.previousValue)
return err
}
}
)
}
18 changes: 11 additions & 7 deletions src/components/hooks/useUpdateWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ export default function useUpdateWidget() {
onSuccess: (updatedInst, variables) => {

// update successful - insert new values into our local copy of widgetList
for (const inst of widgetList?.pagination) {
if (inst.id === variables.args[0]) {
inst.open_at = `${variables.args[4]}`
inst.close_at = `${variables.args[5]}`
inst.attempts = `${variables.args[6]}`
inst.guest_access = variables.args[7]
inst.embedded_only = variables.args[8]
for (const page of widgetList?.pages) {
for (const inst of page?.pagination) {
if (inst.id === variables.args[0]) {
inst.open_at = `${variables.args[4]}`
inst.close_at = `${variables.args[5]}`
inst.attempts = `${variables.args[6]}`
inst.guest_access = variables.args[7]
inst.embedded_only = variables.args[8]
break
}
}
}


// update query cache for widgets. This does NOT invalidate the cache, forcing a re-fetch!!
queryClient.setQueryData('widgets', widgetList)
Expand Down
9 changes: 9 additions & 0 deletions src/components/include.scss
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,15 @@ header {
display: flex;
flex-direction: column;
gap: 5px;

.subject {
line-height: 1.5em;

a {
font-weight: bold;
text-decoration: underline;
}
}
}
.grantAccessTitle
{
Expand Down
Loading

0 comments on commit 1d8ffbf

Please sign in to comment.