From f51e616f6b93a2367066ccc5cd6e7f3d5800fd30 Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Fri, 12 Jul 2019 16:03:10 +0200 Subject: [PATCH 01/46] Return last change upon fetching repo list --- server/course/course.controller.js | 10 +++++++++- server/course/course.model.js | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/server/course/course.controller.js b/server/course/course.controller.js index c62f3efdc..4071b5720 100644 --- a/server/course/course.controller.js +++ b/server/course/course.controller.js @@ -1,6 +1,6 @@ 'use strict'; -const { Course, CourseUser, User } = require('../shared/database'); +const { Course, CourseUser, User, Revision } = require('../shared/database'); const { createContentInventory } = require('../integrations/knewton'); const { createError } = require('../shared/error/helpers'); const { getSchema } = require('../../config/shared/activities'); @@ -16,6 +16,14 @@ const DEFAULT_COLORS = ['#689F38', '#FF5722', '#2196F3']; function index({ query, user, opts }, res) { if (query.search) opts.where.name = { [Op.iLike]: `%${query.search}%` }; + opts.include = [{ + model: Revision, + as: 'revisions', + include: [{ model: User, attributes: ['id', 'email'] }], + order: [['createdAt', 'DESC']], + limit: 1 + }]; + opts.order = [['createdAt', 'DESC']]; const courses = user.isAdmin() ? Course.findAll(opts) : user.getCourses(opts); return courses.then(data => res.json({ data })); } diff --git a/server/course/course.model.js b/server/course/course.model.js index aec2511be..8c3cffd56 100644 --- a/server/course/course.model.js +++ b/server/course/course.model.js @@ -50,7 +50,7 @@ class Course extends Model { }; } - static associate({ Activity, Comment, CourseUser, TeachingElement, User }) { + static associate({ Activity, Comment, CourseUser, Revision, TeachingElement, User }) { this.hasMany(Activity, { foreignKey: { name: 'courseId', field: 'course_id' } }); @@ -60,6 +60,9 @@ class Course extends Model { this.hasMany(TeachingElement, { foreignKey: { name: 'courseId', field: 'course_id' } }); + this.hasMany(Revision, { + foreignKey: { name: 'courseId', field: 'course_id' } + }); this.belongsToMany(User, { through: CourseUser, foreignKey: { name: 'courseId', field: 'course_id' } From 103c23515207d539d829246702644f8f05d8651d Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Fri, 12 Jul 2019 17:04:21 +0200 Subject: [PATCH 02/46] Revamped catalog card --- client/components/catalog/Card.vue | 95 +++++++++++++++++++ client/components/catalog/Card/Stat.vue | 27 ------ client/components/catalog/Card/index.vue | 113 ----------------------- 3 files changed, 95 insertions(+), 140 deletions(-) create mode 100644 client/components/catalog/Card.vue delete mode 100644 client/components/catalog/Card/Stat.vue delete mode 100644 client/components/catalog/Card/index.vue diff --git a/client/components/catalog/Card.vue b/client/components/catalog/Card.vue new file mode 100644 index 000000000..44aba7d37 --- /dev/null +++ b/client/components/catalog/Card.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/client/components/catalog/Card/Stat.vue b/client/components/catalog/Card/Stat.vue deleted file mode 100644 index 70bf359e2..000000000 --- a/client/components/catalog/Card/Stat.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/client/components/catalog/Card/index.vue b/client/components/catalog/Card/index.vue deleted file mode 100644 index 351c7524d..000000000 --- a/client/components/catalog/Card/index.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - From dadfad94c709c456d8f128e6cbb91a78f0a1c5f7 Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Fri, 12 Jul 2019 17:28:11 +0200 Subject: [PATCH 03/46] Updated catalog container - Replaced bootstrap grid with vuetify one --- client/components/catalog/Container.vue | 101 +++++++++++++----------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/client/components/catalog/Container.vue b/client/components/catalog/Container.vue index 064cb6bbd..3dd4cafbc 100644 --- a/client/components/catalog/Container.vue +++ b/client/components/catalog/Container.vue @@ -1,44 +1,50 @@ From bae6eb85ee140e863de644f8aabed2483a772c6d Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Fri, 12 Jul 2019 17:29:53 +0200 Subject: [PATCH 04/46] Renamed default schema --- config/shared/activities-rc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/shared/activities-rc.js b/config/shared/activities-rc.js index 1b99c4e83..6546bd95c 100644 --- a/config/shared/activities-rc.js +++ b/config/shared/activities-rc.js @@ -16,7 +16,7 @@ const CONTENT_CONTAINERS = [{ const SCHEMAS = [{ id: 'DEFAULT_SCHEMA', - name: 'Default schema', + name: 'Sample course', meta: [], structure: [{ level: 1, From 04f70936c91270aaa5b37ff5af2d5cb3bc4d40d8 Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Sun, 14 Jul 2019 15:37:51 +0200 Subject: [PATCH 05/46] Created simple sorting component - WIP --- client/components/catalog/SelectOrder.vue | 55 +++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 client/components/catalog/SelectOrder.vue diff --git a/client/components/catalog/SelectOrder.vue b/client/components/catalog/SelectOrder.vue new file mode 100644 index 000000000..e9783824b --- /dev/null +++ b/client/components/catalog/SelectOrder.vue @@ -0,0 +1,55 @@ + + + + + From 26b1666aee71b6ec3ed6bc1f3d4ab8d4988be327 Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Sun, 14 Jul 2019 15:55:29 +0200 Subject: [PATCH 06/46] Added pinned attr to the courseUser model - Ability to pin repo on dashboard --- server/course/courseUser.model.js | 6 +++++- .../migrations/20190712153652-pin-repo.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 server/shared/database/migrations/20190712153652-pin-repo.js diff --git a/server/course/courseUser.model.js b/server/course/courseUser.model.js index db17ae4b9..12ab9ce52 100644 --- a/server/course/courseUser.model.js +++ b/server/course/courseUser.model.js @@ -4,7 +4,7 @@ const { course: role } = require('../../config/shared').role; const { Model } = require('sequelize'); class CourseUser extends Model { - static fields({ INTEGER, DATE, ENUM }) { + static fields({ BOOLEAN, DATE, ENUM, INTEGER }) { return { userId: { type: INTEGER, @@ -22,6 +22,10 @@ class CourseUser extends Model { type: ENUM(role.ADMIN, role.AUTHOR), defaultValue: role.AUTHOR }, + pinned: { + type: BOOLEAN, + defaultValue: false + }, createdAt: { type: DATE, field: 'created_at' diff --git a/server/shared/database/migrations/20190712153652-pin-repo.js b/server/shared/database/migrations/20190712153652-pin-repo.js new file mode 100644 index 000000000..ec5f46a94 --- /dev/null +++ b/server/shared/database/migrations/20190712153652-pin-repo.js @@ -0,0 +1,16 @@ +'use strict'; + +const TABLE_NAME = 'course_user'; +const COLUMN_NAME = 'pinned'; + +module.exports = { + up: (queryInterface, { BOOLEAN }) => { + return queryInterface.addColumn(TABLE_NAME, COLUMN_NAME, { + type: BOOLEAN, + defaultValue: false + }); + }, + down: (queryInterface) => { + return queryInterface.removeColumn(TABLE_NAME, COLUMN_NAME); + } +}; From 24148123fa2f42ad232043913083ad3070567fd1 Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Sun, 14 Jul 2019 15:57:15 +0200 Subject: [PATCH 07/46] Added missing courseUser relationship :wrench: --- server/course/course.model.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/course/course.model.js b/server/course/course.model.js index 8c3cffd56..044b2a126 100644 --- a/server/course/course.model.js +++ b/server/course/course.model.js @@ -63,6 +63,9 @@ class Course extends Model { this.hasMany(Revision, { foreignKey: { name: 'courseId', field: 'course_id' } }); + this.hasMany(CourseUser, { + foreignKey: { name: 'courseId', field: 'course_id' } + }); this.belongsToMany(User, { through: CourseUser, foreignKey: { name: 'courseId', field: 'course_id' } From c00ec1ba93900705d6ca26a7010c06e2d59a4e0e Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Sun, 14 Jul 2019 16:12:00 +0200 Subject: [PATCH 08/46] Course ctrl updates - Ability to pin a course - Fetching last revision and courseUser record upon listing courses - Ability to do case insensitive sort by name - WIP --- server/course/course.controller.js | 19 ++++++++++++++++--- server/course/index.js | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/server/course/course.controller.js b/server/course/course.controller.js index 4071b5720..ba9d303b3 100644 --- a/server/course/course.controller.js +++ b/server/course/course.controller.js @@ -1,6 +1,6 @@ 'use strict'; -const { Course, CourseUser, User, Revision } = require('../shared/database'); +const { Course, CourseUser, User, Revision, sequelize } = require('../shared/database'); const { createContentInventory } = require('../integrations/knewton'); const { createError } = require('../shared/error/helpers'); const { getSchema } = require('../../config/shared/activities'); @@ -13,17 +13,21 @@ const publishingService = require('../shared/publishing/publishing.service'); const sample = require('lodash/sample'); const DEFAULT_COLORS = ['#689F38', '#FF5722', '#2196F3']; +const lowercaseName = sequelize.fn('lower', sequelize.col('name')); function index({ query, user, opts }, res) { if (query.search) opts.where.name = { [Op.iLike]: `%${query.search}%` }; + if (getVal(opts, 'order.0.0') === 'name') opts.order[0][0] = lowercaseName; opts.include = [{ model: Revision, - as: 'revisions', include: [{ model: User, attributes: ['id', 'email'] }], order: [['createdAt', 'DESC']], limit: 1 }]; - opts.order = [['createdAt', 'DESC']]; + const courseUser = query.pinned + ? { where: { userId: user.id, pinned: true }, required: true } + : { where: { userId: user.id }, required: false }; + opts.include.push({ model: CourseUser, ...courseUser }); const courses = user.isAdmin() ? Course.findAll(opts) : user.getCourses(opts); return courses.then(data => res.json({ data })); } @@ -53,6 +57,14 @@ function remove({ course, user }, res) { .then(() => res.status(204).send()); } +async function pin({ user, course, body }, res) { + const opts = { where: { courseId: course.id, userId: user.id } }; + const [courseUser] = await CourseUser.findOrCreate(opts); + courseUser.pinned = body.pin; + await courseUser.save(); + return res.json({ data: courseUser }); +} + function clone({ user, course, body }, res) { const { name, description } = body; const context = { userId: user.id }; @@ -118,6 +130,7 @@ module.exports = { get, patch, remove, + pin, clone, getUsers, upsertUser, diff --git a/server/course/index.js b/server/course/index.js index 40ef8dcc4..92476d12a 100644 --- a/server/course/index.js +++ b/server/course/index.js @@ -16,6 +16,7 @@ router .get('/courses/:id', ctrl.get) .patch('/courses/:id', ctrl.patch) .delete('/courses/:id', ctrl.remove) + .post('/courses/:id/pin', ctrl.pin) .post('/courses/:id/clone', authorize(), ctrl.clone) .post('/courses/:id/publish', ctrl.publishRepoInfo) .get('/courses/:id/users', ctrl.getUsers) From 2baa5a76717f1ff8d9d8e5aac943993593d97b22 Mon Sep 17 00:00:00 2001 From: Damir Perisic Date: Sun, 14 Jul 2019 16:13:22 +0200 Subject: [PATCH 09/46] :lipstick: --- client/components/catalog/Search.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/components/catalog/Search.vue b/client/components/catalog/Search.vue index c299e4d67..96a77e73d 100644 --- a/client/components/catalog/Search.vue +++ b/client/components/catalog/Search.vue @@ -1,7 +1,7 @@