Add course/session list, fix menu depending in user role.

pull/3272/head
Julio Montoya 5 years ago
parent 030eb8b84c
commit ddfd23a186
  1. 17
      .eslintrc.json
  2. 71
      assets/vue/App.vue
  3. 4
      assets/vue/router/index.js
  4. 10
      assets/vue/store/security.js
  5. 38
      assets/vue/views/user/courses/CourseCard.vue
  6. 45
      assets/vue/views/user/courses/List.vue
  7. 43
      assets/vue/views/user/sessions/List.vue
  8. 26
      assets/vue/views/user/sessions/SessionCard.vue
  9. 20
      src/CoreBundle/Entity/Course.php
  10. 7
      src/CoreBundle/Entity/CourseRelUser.php
  11. 4
      src/CoreBundle/Entity/Session.php
  12. 10
      src/CoreBundle/Entity/SessionRelCourseRelUser.php
  13. 12
      src/CoreBundle/Entity/User.php

@ -0,0 +1,17 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"parser": "babel-eslint"
},
"env": {
"browser": true,
"node": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:vue/recommended"
]
}

@ -7,7 +7,6 @@
v-model="drawer" v-model="drawer"
:clipped="$vuetify.breakpoint.lgAndUp" :clipped="$vuetify.breakpoint.lgAndUp"
disable-resize-watcher disable-resize-watcher
> >
<v-list v-if="isAuthenticated"> <v-list v-if="isAuthenticated">
<v-list-item :to="{ name: '/' }"> <v-list-item :to="{ name: '/' }">
@ -21,7 +20,30 @@
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
<v-list-item :to="{ name: 'MyCourses' }">
<v-list-item-action>
<v-icon>mdi-home</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
My courses
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item :to="{ name: 'MySessions' }">
<v-list-item-action>
<v-icon>mdi-home</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
My sessions
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-group <v-list-group
v-if="isAdmin"
prepend-icon="mdi-plus" prepend-icon="mdi-plus"
value="true" value="true"
> >
@ -170,9 +192,38 @@
</v-toolbar-title> </v-toolbar-title>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn icon v-if="isAuthenticated"> <v-menu
<v-icon>mdi-bell</v-icon> v-if="isAuthenticated"
offset-y
:nudge-width="200"
>
<template v-slot:activator="{ on }">
<v-btn icon v-on="on">
<v-avatar>
<v-icon dark>mdi-bell</v-icon>
</v-avatar>
</v-btn> </v-btn>
</template>
<v-card>
<v-card-text>
<div>Notifications</div>
</v-card-text>
<v-list>
<v-list-item>
<v-list-item-title>
Notification 1
</v-list-item-title>
</v-list-item>
<v-list-item>
<v-list-item-title>
Notification 2
</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-menu>
<v-menu <v-menu
v-if="isAuthenticated" v-if="isAuthenticated"
@ -189,6 +240,10 @@
<v-list-item> <v-list-item>
<v-list-item-title>Profile</v-list-item-title> <v-list-item-title>Profile</v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item>
<v-list-item-title>Inbox</v-list-item-title>
</v-list-item>
<v-list-item> <v-list-item>
<v-list-item-title> <v-list-item-title>
<a href="/logout">Logout</a> <a href="/logout">Logout</a>
@ -257,20 +312,20 @@
isAuthenticated() { isAuthenticated() {
return this.$store.getters['security/isAuthenticated'] return this.$store.getters['security/isAuthenticated']
}, },
isAdmin() {
return this.$store.getters['security/isAdmin']
},
}, },
watch: { watch: {
$route(to, from) { $route(to, from) {
console.log('remove');
this.$data.legacy_content = ''; this.$data.legacy_content = '';
if (document.querySelector("#sectionMainContent")) { if (document.querySelector("#sectionMainContent")) {
console.log('removed sectionMainContent');
document.querySelector("#sectionMainContent").remove(); document.querySelector("#sectionMainContent").remove();
} }
let url = window.location.href; let url = window.location.href;
console.log(url); console.log(url);
var n = url.indexOf("main/"); var n = url.indexOf("main/");
if (n > 0) { if (n > 0) {
console.log('ajax');
axios.get(url, { axios.get(url, {
params: { params: {
from_vue: 1 from_vue: 1
@ -284,17 +339,13 @@
}, },
legacy_content: { legacy_content: {
handler: function () { handler: function () {
console.log('watch');
if (document.querySelector("#sectionMainContent")) { if (document.querySelector("#sectionMainContent")) {
//console.log('removed sectionMainContent');
//document.querySelector("#sectionMainContent").remove();
} }
}, },
immediate: true immediate: true
}, },
}, },
mounted() { mounted() {
console.log('mounted');
let legacyContent = document.querySelector("#sectionMainContent"); let legacyContent = document.querySelector("#sectionMainContent");
if (legacyContent) { if (legacyContent) {
document.querySelector("#sectionMainContent").remove(); document.querySelector("#sectionMainContent").remove();

@ -8,11 +8,15 @@ import courseCategoryRoutes from './coursecategory';
import documents from './documents'; import documents from './documents';
import store from "../store"; import store from "../store";
import Login from "../views/Login"; import Login from "../views/Login";
import MyCourseList from "../views/user/courses/List";
import MySessionList from "../views/user/sessions/List";
let router = new VueRouter({ let router = new VueRouter({
mode: "history", mode: "history",
routes: [ routes: [
{ path: "/login", component: Login }, { path: "/login", component: Login },
{ path: "/courses", name: "MyCourses", component: MyCourseList },
{ path: "/sessions", name: "MySessions", component: MySessionList },
courseRoutes, courseRoutes,
courseCategoryRoutes, courseCategoryRoutes,
documents documents

@ -26,10 +26,20 @@ export default {
isAuthenticated(state) { isAuthenticated(state) {
return state.isAuthenticated; return state.isAuthenticated;
}, },
isAdmin(state, getters) {
return getters.hasRole('ROLE_ADMIN');
},
getUser(state) {
return state.user;
},
hasRole(state) { hasRole(state) {
return role => { return role => {
if (state.user.roles) {
return state.user.roles.indexOf(role) !== -1; return state.user.roles.indexOf(role) !== -1;
} }
return false;
}
} }
}, },
mutations: { mutations: {

@ -0,0 +1,38 @@
<template>
<v-container grid-list-xl fluid>
<v-layout row wrap>
<v-row dense>
<v-col
v-for="card in courses"
:key="card.course.id"
:cols="12"
>
<v-card>
<v-card-title v-text="card.course.title">
</v-card-title>
<v-card-actions>
<v-btn
:href=" '/course/' + card.course.id + '/home'"
text
color="deep-purple accent-4"
>
Go
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-layout>
</v-container>
</template>
<script>
export default {
name: 'CourseCard',
props: {
courses: Array
},
};
</script>

@ -0,0 +1,45 @@
<template>
<div class="course-list">
{{ status }}
<CourseCard :courses="courses"></CourseCard>
</div>
</template>
<script>
import CourseCard from './CourseCard';
import ListMixin from '../../../mixins/ListMixin';
import { ENTRYPOINT } from '../../../config/entrypoint';
import axios from "axios";
export default {
name: 'CourseList',
servicePrefix: 'Course',
mixins: [ListMixin],
components: {
CourseCard
},
data() {
return {
status: null,
courses:null
};
},
created: function () {
this.load();
},
methods: {
load: function() {
this.status = 'Loading';
let user = this.$store.getters['security/getUser'];
axios.get(ENTRYPOINT + 'users/'+ user.id +'/courses.json').then(response => {
this.status = '';
this.courses = response.data;
}).catch(function(error) {
this.status = error;
});
}
}
};
</script>

@ -0,0 +1,43 @@
<template>
<div class="course-list">
{{ status }}
<SessionCard :sessions="sessions"></SessionCard>
</div>
</template>
<script>
import SessionCard from './SessionCard';
import ListMixin from '../../../mixins/ListMixin';
import { ENTRYPOINT } from '../../../config/entrypoint';
import axios from "axios";
export default {
name: 'SessionList',
servicePrefix: 'Course',
mixins: [ListMixin],
components: {
SessionCard
},
data() {
return {
status: null,
sessions:null
};
},
created: function () {
this.load();
},
methods: {
load: function() {
this.status = 'Loading';
let user = this.$store.getters['security/getUser'];
axios.get(ENTRYPOINT + 'users/' + user.id + '/session_course_subscriptions.json').then(response => {
this.status = '';
this.sessions = response.data;
}).catch(function (error) {
this.status = error;
});
}
}
};
</script>

@ -0,0 +1,26 @@
<template>
<v-container grid-list-xl fluid>
<v-layout row wrap>
<v-row dense>
<v-col
v-for="card in sessions"
:key="card.course.title"
:cols="12"
>
<v-card>
<v-card-title v-text="card.course.title"></v-card-title>
</v-card>
</v-col>
</v-row>
</v-layout>
</v-container>
</template>
<script>
export default {
name: 'SessionCard',
props: {
sessions: Array
},
};
</script>

@ -58,7 +58,7 @@ class Course extends AbstractResource implements ResourceInterface
/** /**
* @var int * @var int
* @Groups({"course:read"}) * @Groups({"course:read", "course_rel_user:read"})
* @ORM\Column(name="id", type="integer", nullable=false, unique=false) * @ORM\Column(name="id", type="integer", nullable=false, unique=false)
* @ORM\Id * @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
@ -70,7 +70,7 @@ class Course extends AbstractResource implements ResourceInterface
* *
* @Assert\NotBlank() * @Assert\NotBlank()
* *
* @Groups({"course:read", "course:write"}) * @Groups({"course:read", "course:write", "course_rel_user:read", "session_rel_course_rel_user:read"})
* *
* @ORM\Column(name="title", type="string", length=250, nullable=true, unique=false) * @ORM\Column(name="title", type="string", length=250, nullable=true, unique=false)
*/ */
@ -80,7 +80,7 @@ class Course extends AbstractResource implements ResourceInterface
* @var string * @var string
* @Assert\NotBlank() * @Assert\NotBlank()
* @ApiProperty(iri="http://schema.org/courseCode") * @ApiProperty(iri="http://schema.org/courseCode")
* @Groups({"course:read", "course:write"}) * @Groups({"course:read", "course:write", "course_rel_user:read"})
* *
* @Gedmo\Slug( * @Gedmo\Slug(
* fields={"title"}, * fields={"title"},
@ -96,7 +96,7 @@ class Course extends AbstractResource implements ResourceInterface
* @var CourseRelUser[]|ArrayCollection * @var CourseRelUser[]|ArrayCollection
* *
* @ApiSubresource() * @ApiSubresource()
* @Groups({"course:read"}) * Groups({"course:read"})
* "orphanRemoval" is needed to delete the CourseRelUser relation * "orphanRemoval" is needed to delete the CourseRelUser relation
* in the CourseAdmin class. The setUsers, getUsers, removeUsers and * in the CourseAdmin class. The setUsers, getUsers, removeUsers and
* addUsers methods need to be added. * addUsers methods need to be added.
@ -154,32 +154,32 @@ class Course extends AbstractResource implements ResourceInterface
protected $currentUrl; protected $currentUrl;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\SkillRelCourse", mappedBy="course", cascade={"persist", "remove"}) * @ORM\OneToMany(targetEntity="SkillRelCourse", mappedBy="course", cascade={"persist", "remove"})
*/ */
protected $skills; protected $skills;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\SkillRelUser", mappedBy="course", cascade={"persist", "remove"}) * @ORM\OneToMany(targetEntity="SkillRelUser", mappedBy="course", cascade={"persist", "remove"})
*/ */
protected $issuedSkills; protected $issuedSkills;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\GradebookCategory", mappedBy="course", cascade={"persist", "remove"}) * @ORM\OneToMany(targetEntity="GradebookCategory", mappedBy="course", cascade={"persist", "remove"})
*/ */
protected $gradebookCategories; protected $gradebookCategories;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\GradebookEvaluation", mappedBy="course", cascade={"persist", "remove"}) * @ORM\OneToMany(targetEntity="GradebookEvaluation", mappedBy="course", cascade={"persist", "remove"})
*/ */
protected $gradebookEvaluations; protected $gradebookEvaluations;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\GradebookLink", mappedBy="course", cascade={"persist", "remove"}) * @ORM\OneToMany(targetEntity="GradebookLink", mappedBy="course", cascade={"persist", "remove"})
*/ */
protected $gradebookLinks; protected $gradebookLinks;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\TrackEHotspot", mappedBy="course", cascade={"persist", "remove"}) * @ORM\OneToMany(targetEntity="TrackEHotspot", mappedBy="course", cascade={"persist", "remove"})
*/ */
protected $trackEHotspots; protected $trackEHotspots;

@ -13,7 +13,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
* *
* @ApiResource( * @ApiResource(
* shortName="CourseSubscription", * shortName="CourseSubscription",
* normalizationContext={"groups"={"course_rel_user:read"}} * normalizationContext={"groups"={"course_rel_user:read", "user:read"}}
* ) * )
* *
* @ORM\Table( * @ORM\Table(
@ -45,6 +45,7 @@ class CourseRelUser
protected $user; protected $user;
/** /**
* @Groups({"course:read", "user:read"})
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course", inversedBy="users", cascade={"persist"}) * @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course", inversedBy="users", cascade={"persist"})
* @ORM\JoinColumn(name="c_id", referencedColumnName="id") * @ORM\JoinColumn(name="c_id", referencedColumnName="id")
*/ */
@ -52,14 +53,14 @@ class CourseRelUser
/** /**
* @var int * @var int
* * @Groups({"user:read", "course:read"})
* @ORM\Column(name="relation_type", type="integer", nullable=false, unique=false) * @ORM\Column(name="relation_type", type="integer", nullable=false, unique=false)
*/ */
protected $relationType; protected $relationType;
/** /**
* @var bool * @var bool
* * @Groups({"user:read"})
* @ORM\Column(name="status", type="integer", nullable=false, unique=false) * @ORM\Column(name="status", type="integer", nullable=false, unique=false)
*/ */
protected $status; protected $status;

@ -113,7 +113,7 @@ class Session
protected $urls; protected $urls;
/** /**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\ResourceLink", mappedBy="session", cascade={"remove"}, orphanRemoval=true) * @ORM\OneToMany(targetEntity="ResourceLink", mappedBy="session", cascade={"remove"}, orphanRemoval=true)
*/ */
protected $resourceLinks; protected $resourceLinks;
@ -125,7 +125,7 @@ class Session
/** /**
* @var string * @var string
* @Assert\NotBlank() * @Assert\NotBlank()
* @Groups({"session:read", "session:write"}) * @Groups({"session:read", "session:write", "session_rel_course_rel_user:read"})
* @ORM\Column(name="name", type="string", length=150, nullable=false, unique=false) * @ORM\Column(name="name", type="string", length=150, nullable=false, unique=false)
*/ */
protected $name; protected $name;

@ -4,11 +4,17 @@
namespace Chamilo\CoreBundle\Entity; namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/** /**
* Class SessionRelCourseRelUser. * Class SessionRelCourseRelUser.
* *
* @ApiResource(
* shortName="SessionSubscription",
* normalizationContext={"groups"={"session_rel_course_rel_user:read", "user:read"}}
* )
* @ORM\Table( * @ORM\Table(
* name="session_rel_course_rel_user", * name="session_rel_course_rel_user",
* indexes={ * indexes={
@ -47,7 +53,7 @@ class SessionRelCourseRelUser
/** /**
* @var Session * @var Session
* * @Groups({"session_rel_course_rel_user:read"})
* @ORM\ManyToOne(targetEntity="Session", inversedBy="userCourseSubscriptions", cascade={"persist"}) * @ORM\ManyToOne(targetEntity="Session", inversedBy="userCourseSubscriptions", cascade={"persist"})
* @ORM\JoinColumn(name="session_id", referencedColumnName="id", nullable=false) * @ORM\JoinColumn(name="session_id", referencedColumnName="id", nullable=false)
*/ */
@ -55,7 +61,7 @@ class SessionRelCourseRelUser
/** /**
* @var Course * @var Course
* * @Groups({"session_rel_course_rel_user:read"})
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course", inversedBy="sessionUserSubscriptions", cascade={"persist"}) * @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course", inversedBy="sessionUserSubscriptions", cascade={"persist"})
* @ORM\JoinColumn(name="c_id", referencedColumnName="id", nullable=false) * @ORM\JoinColumn(name="c_id", referencedColumnName="id", nullable=false)
*/ */

@ -277,6 +277,7 @@ class User implements UserInterface, EquatableInterface
protected $dropBoxSentFiles; protected $dropBoxSentFiles;
/** /**
* @Groups({"user:read", "user:write"})
* @ORM\Column(type="array") * @ORM\Column(type="array")
*/ */
protected $roles; protected $roles;
@ -344,6 +345,7 @@ class User implements UserInterface, EquatableInterface
protected $resourceNodes; protected $resourceNodes;
/** /**
* @ApiSubresource()
* @ORM\OneToMany( * @ORM\OneToMany(
* targetEntity="Chamilo\CoreBundle\Entity\SessionRelCourseRelUser", * targetEntity="Chamilo\CoreBundle\Entity\SessionRelCourseRelUser",
* mappedBy="user", * mappedBy="user",
@ -918,16 +920,6 @@ class User implements UserInterface, EquatableInterface
return \UserManager::formatUserFullName($this).$classString; return \UserManager::formatUserFullName($this).$classString;
} }
/**
* Get userId.
*
* @return int
*/
public function getUserId()
{
return $this->userId;
}
/** /**
* Set lastname. * Set lastname.
* *

Loading…
Cancel
Save