mumuki-laboratory 9.0.0 → 9.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mumuki_laboratory/application/certificate.js +17 -0
  3. data/app/assets/javascripts/mumuki_laboratory/application/discussions.js +43 -2
  4. data/app/assets/javascripts/mumuki_laboratory/application/faqs.js +90 -0
  5. data/app/assets/javascripts/mumuki_laboratory/application/organization.js +32 -0
  6. data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +1 -1
  7. data/app/assets/javascripts/mumuki_laboratory/application/user.js +49 -5
  8. data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +3 -0
  9. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_activity.scss +12 -0
  10. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_certificate.scss +33 -0
  11. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_discussion.scss +14 -2
  12. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_faqs.scss +84 -0
  13. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_menu.scss +30 -2
  14. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +1 -0
  15. data/app/controllers/certificates_controller.rb +28 -0
  16. data/app/controllers/concerns/with_certificate_render.rb +25 -0
  17. data/app/controllers/discussions_messages_controller.rb +6 -2
  18. data/app/controllers/faqs_controller.rb +6 -0
  19. data/app/controllers/users_controller.rb +17 -0
  20. data/app/helpers/certificate_helper.rb +13 -0
  21. data/app/helpers/discussions_helper.rb +5 -1
  22. data/app/helpers/links_helper.rb +9 -1
  23. data/app/helpers/menu_bar_helper.rb +14 -10
  24. data/app/helpers/user_activity_helper.rb +48 -0
  25. data/app/helpers/user_menu_helper.rb +27 -5
  26. data/app/mailers/application_mailer.rb +0 -1
  27. data/app/mailers/user_mailer.rb +9 -0
  28. data/app/views/certificates/_certificate.html.erb +44 -0
  29. data/app/views/certificates/_download.html.erb +20 -0
  30. data/app/views/certificates/verify.html.erb +40 -0
  31. data/app/views/discussions/_description_message.html.erb +1 -1
  32. data/app/views/discussions/_message.html.erb +1 -1
  33. data/app/views/discussions/_new_message.html.erb +13 -2
  34. data/app/views/discussions/new.html.erb +1 -1
  35. data/app/views/faqs/index.html.erb +20 -0
  36. data/app/views/layouts/_main.html.erb +4 -0
  37. data/app/views/layouts/_user_menu.html.erb +12 -16
  38. data/app/views/layouts/application.html.erb +6 -1
  39. data/app/views/layouts/exercise_inputs/editors/_code.html.erb +2 -1
  40. data/app/views/user_mailer/certificate.html.erb +339 -0
  41. data/app/views/user_mailer/certificate.text.erb +10 -0
  42. data/app/views/users/_activity_indicator.html.erb +17 -0
  43. data/app/views/users/activity.html.erb +37 -0
  44. data/app/views/users/certificates.html.erb +32 -0
  45. data/config/routes.rb +9 -0
  46. data/lib/mumuki/laboratory/extensions.rb +1 -0
  47. data/lib/mumuki/laboratory/extensions/date_and_time.rb +11 -0
  48. data/lib/mumuki/laboratory/locales/en.yml +20 -1
  49. data/lib/mumuki/laboratory/locales/es-CL.yml +25 -3
  50. data/lib/mumuki/laboratory/locales/es.yml +25 -3
  51. data/lib/mumuki/laboratory/locales/pt.yml +26 -1
  52. data/lib/mumuki/laboratory/version.rb +1 -1
  53. data/spec/controllers/certificates_controller_spec.rb +15 -0
  54. data/spec/controllers/discussions_messages_controller_spec.rb +20 -1
  55. data/spec/dummy/db/schema.rb +5 -1
  56. data/spec/features/certificate_programs_flow_spec.rb +17 -0
  57. data/spec/features/discussion_flow_spec.rb +2 -0
  58. data/spec/features/menu_bar_spec.rb +20 -0
  59. data/spec/features/profile_flow_spec.rb +12 -0
  60. data/spec/features/user_activity_flow_spec.rb +65 -0
  61. data/spec/helpers/application_helper_spec.rb +10 -0
  62. data/spec/helpers/certificate_helper_spec.rb +15 -0
  63. data/spec/helpers/user_activity_helper_spec.rb +32 -0
  64. metadata +171 -99
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96b344d472912c433732e101f0754c229aa8c406e47a2ff54503a9625bb78f5a
4
- data.tar.gz: b73fba56c2c87069b1e402ce010eaa17d296220c92df9cc241d92e9aa92eb909
3
+ metadata.gz: d72de447465b6716ee6b249aae76c6158aaa6ca02c87d58ea4e19fcf783ad85e
4
+ data.tar.gz: 387fef678b907e118266847df85eada3fb2aaea616162bb00e136776f2010629
5
5
  SHA512:
6
- metadata.gz: b2557a3374e33d3a273b4df24cdd5eb3e46d0e997af5a862c6b6a6cd792a63c4a78e6c248927efeaf964d275139923cea0292a204b92448a965614c2b1f0f82f
7
- data.tar.gz: 2667001640a346bd3517445621adb899599b52a44d7c40625a6ae67e7a46e7c5c2d935501358b5a28e5ebeb6aa7a0da58cc4af0cf74fb2a7706d738577d47837
6
+ metadata.gz: ae0f9022a999d502065a58c4fca2224c4ea3f21562c56d55489889793d70c7d561554bbd2eeb0f940295a7fc071adac35cf439219b228aa150799c62ed9f6a25
7
+ data.tar.gz: 5e40cd1dc2accffef46a0a6981d0ad588f031070c611d67d8c0811cdd6919a6d4733b8363b1bf6d02018c41f9d72945c4b6b497bc465ebe6621c00e17087d6c5
@@ -0,0 +1,17 @@
1
+ mumuki.load(() => {
2
+ scaleCertificate();
3
+ mumuki.resize(scaleCertificate);
4
+
5
+ function scaleCertificate() {
6
+ const $certPreview = $('.certificate-preview');
7
+ const $muCertificate = $('.mu-certificate-box');
8
+ $muCertificate.css('transform', 'scale(1)');
9
+
10
+ const scaleWidth = $muCertificate.width() / $certPreview.width();
11
+ $muCertificate.css({
12
+ 'transform': `scale(${1 / scaleWidth})`,
13
+ 'transform-origin': `0 0`,
14
+ });
15
+ $certPreview.height($muCertificate.height());
16
+ }
17
+ });
@@ -1,9 +1,13 @@
1
1
  mumuki.load(() => {
2
2
  var $subscriptionSpans = $('.discussion-subscription > span');
3
3
  var $upvoteSpans = $('.discussion-upvote > span');
4
+ let $messagePreviewButton = $('.discussion-new-message-preview-button.preview');
5
+ let $messageEditButton = $('.discussion-new-message-preview-button.edit');
6
+ let $newMessageContent = $('.discussion-new-message-content');
7
+ let $newMessagePreview = $('#discussion-new-message-preview');
4
8
 
5
9
  function createNewMessageEditor() {
6
- var $textarea = $("#new-discussion-message");
10
+ var $textarea = $("#discussion-new-message");
7
11
  var textarea = $textarea[0];
8
12
  if (!textarea) return;
9
13
 
@@ -26,7 +30,7 @@ mumuki.load(() => {
26
30
  }
27
31
 
28
32
  createReadOnlyEditors();
29
- createNewMessageEditor();
33
+ let editor = createNewMessageEditor();
30
34
 
31
35
  var Forum = {
32
36
  toggleButton: function (spans) {
@@ -67,9 +71,46 @@ mumuki.load(() => {
67
71
  const params = new URLSearchParams(location.search);
68
72
  elem.is(':checked') ? params.set(key, elem.val()) : params.delete(key);
69
73
  location.search = params.toString();
74
+ },
75
+ discussionMessagePreview: function (url) {
76
+ return Forum.tokenRequest({
77
+ url: url,
78
+ method: 'GET',
79
+ processData: false,
80
+ dataType: 'json',
81
+ data: new URLSearchParams({ content: editor.getValue() } ),
82
+ success: function (response) {
83
+ showPreview(response.preview);
84
+ },
85
+ error: function (e) {
86
+ error = $messagePreviewButton.attr('error-text');
87
+ showPreview(error);
88
+ },
89
+ xhrFields: {withCredentials: true}
90
+ });
91
+ },
92
+ hidePreviewAndShowEditor: function(elem) {
93
+ togglePreviewAndEditButtons();
94
+ togglePreviewAndContentMessage();
70
95
  }
71
96
  };
72
97
 
98
+ function showPreview(preview) {
99
+ $newMessagePreview.html($.parseHTML(preview));
100
+ togglePreviewAndEditButtons();
101
+ togglePreviewAndContentMessage();
102
+ }
103
+
104
+ function togglePreviewAndEditButtons() {
105
+ $messagePreviewButton.toggleClass('hidden');
106
+ $messageEditButton.toggleClass('hidden');
107
+ }
108
+
109
+ function togglePreviewAndContentMessage() {
110
+ $newMessagePreview.toggleClass('hidden');
111
+ $newMessageContent.toggleClass('hidden');
112
+ }
113
+
73
114
  mumuki.Forum = Forum;
74
115
 
75
116
  });
@@ -0,0 +1,90 @@
1
+ mumuki.faqs = class {
2
+
3
+ constructor() {
4
+ this.faqs = $('.mu-faqs');
5
+ this.topHierarchyElem = "H2";
6
+ }
7
+
8
+ // ================
9
+ // == Public API ==
10
+ // ================
11
+
12
+ /**
13
+ * Actually setup the faqs page
14
+ */
15
+ load() {
16
+ if(!this.faqs) return;
17
+ this._createFaqsGroups();
18
+ this._createNavbar();
19
+ }
20
+
21
+ // =================
22
+ // == Private API ==
23
+ // =================
24
+
25
+ _createNavbar() {
26
+ const $faqsNavbar = $(".mu-faqs-navbar nav ul");
27
+ $('.mu-faqs-group').each((_index, faqGroup) => {
28
+ const $navItem = this._createNavbarItem($faqsNavbar, faqGroup)
29
+ const $faqGroup = $(faqGroup);
30
+ this._configureClickFor($navItem, $faqGroup, $faqsNavbar)
31
+ });
32
+ }
33
+
34
+ _createNavbarItem($faqsNavbar, faqGroup) {
35
+ const $navItem = $(`<li><a href="#${faqGroup.id}">`)
36
+ .html(`${faqGroup.querySelector('h2').textContent}`);
37
+ $faqsNavbar.append($navItem);
38
+ return $navItem;
39
+ }
40
+
41
+ _configureClickFor($navItem, $faqGroup, $faqsNavbar) {
42
+ $navItem.click(function(e){
43
+ e.preventDefault();
44
+ $faqsNavbar.find('li').removeClass('active');
45
+ $navItem.addClass('active');
46
+ $('html, body').animate({scrollTop: $faqGroup.offset().top}, 1000);
47
+ });
48
+ }
49
+
50
+ _createFaqsGroups() {
51
+ const elemsGroups = this._buildFaqsGroups();
52
+ elemsGroups.forEach((group, index) => {
53
+ $(group).wrapAll(`<div class='mu-faqs-group' id='mu-faqs-group-${index}'>`);
54
+ });
55
+ this._createFaqsIcons();
56
+ }
57
+
58
+ _createFaqsIcons() {
59
+ const $faqIcon = $('<i class="mu-faqs-group-icon fa fa-plus">');
60
+ $faqIcon.click(function(e){
61
+ const $elem = $(this);
62
+ $elem.toggleClass('fa-plus fa-minus');
63
+ $elem.closest('.mu-faqs-group').toggleClass('active');
64
+ })
65
+ $('.mu-faqs-group').prepend($faqIcon);
66
+ }
67
+
68
+ _buildFaqsGroups() {
69
+ let newGroup = [];
70
+ let elemsGroups = [];
71
+ let previousNodeName;
72
+ $(".mu-faqs-content").children().each((index, elem) => {
73
+ if(elem.nodeName === this.topHierarchyElem && newGroup.length) {
74
+ elemsGroups.push(newGroup);
75
+ newGroup = [];
76
+ }
77
+ newGroup.push(elem);
78
+ previousNodeName = elem.nodeName
79
+ });
80
+
81
+ elemsGroups.push(newGroup);
82
+
83
+ return elemsGroups;
84
+ }
85
+
86
+ };
87
+
88
+ mumuki.load(() => {
89
+ new mumuki.faqs().load();
90
+ });
@@ -0,0 +1,32 @@
1
+ mumuki.organization = {
2
+
3
+ /**
4
+ * The current organization's id
5
+ *
6
+ * @type {number?}
7
+ * */
8
+ _id: null,
9
+
10
+ /**
11
+ * The current organization's id
12
+ *
13
+ * @type {number?}
14
+ * */
15
+ get id() {
16
+ return this._id;
17
+ },
18
+
19
+ /**
20
+ * Set global current organization information
21
+ */
22
+ load() {
23
+ const $muOrganizationId = $('#mu-organization-id');
24
+ if ($muOrganizationId.length) {
25
+ this._id = $muOrganizationId.val();
26
+ } else {
27
+ this._id = null;
28
+ }
29
+ }
30
+ };
31
+
32
+ mumuki.load(() => mumuki.organization.load());
@@ -94,7 +94,7 @@ mumuki.SubmissionsStore = (() => {
94
94
  }
95
95
 
96
96
  _keyFor(exerciseId) {
97
- return `/exercise/${exerciseId}/submission`;
97
+ return `/organization/${mumuki.organization.id}/user/${mumuki.user.id}/exercise/${exerciseId}/submission`;
98
98
  }
99
99
  }();
100
100
 
@@ -1,9 +1,53 @@
1
+ mumuki.user = {
2
+
3
+ /**
4
+ * The current user's id
5
+ *
6
+ * @type {number?}
7
+ * */
8
+ _id: null,
9
+
10
+ /**
11
+ * The current user's id
12
+ *
13
+ * @type {number?}
14
+ * */
15
+ get id() {
16
+ return this._id;
17
+ },
18
+
19
+ /**
20
+ * Set global current user information
21
+ */
22
+ load() {
23
+ const $muUserId = $('#mu-user-id');
24
+ if ($muUserId.length) {
25
+ this._id = $muUserId.val();
26
+ } else {
27
+ this._id = null;
28
+ }
29
+ }
30
+ };
31
+
1
32
  mumuki.load(() => {
2
- var hash = document.location.hash;
3
- if (hash) {
4
- $(".nav-tabs a[data-target='" + hash + "']").tab('show');
33
+ const $userMenuHeader = $('.mu-user-menu-header');
34
+ let onUserProfile = document.querySelector('.mu-profile-info') !== null;
35
+
36
+ $userMenuHeader.click(() => {
37
+ $('.mu-user-menu-items').toggleClass('mu-hidden-sm-screen');
38
+ $('#mu-user-menu-header-icon').toggleClass('fa-chevron-up fa-chevron-down');
39
+ });
40
+
41
+ if (onUserProfile) {
42
+ $userMenuHeader.click();
5
43
  }
6
- $('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
7
- window.location.hash = $(e.target).attr('data-target');
44
+
45
+ $('.mu-user-menu-item .active').click((e) => {
46
+ if (onUserProfile) {
47
+ e.preventDefault();
48
+ $userMenuHeader.click();
49
+ }
8
50
  });
51
+
52
+ mumuki.user.load()
9
53
  });
@@ -1,6 +1,8 @@
1
+ @import "modules/activity";
1
2
  @import "modules/avatar";
2
3
  @import "modules/book_header";
3
4
  @import "modules/breadcrumb";
5
+ @import "modules/certificate";
4
6
  @import "modules/checkboxes";
5
7
  @import "modules/console";
6
8
  @import "modules/content_show";
@@ -10,6 +12,7 @@
10
12
  @import "modules/editor";
11
13
  @import "modules/exercise_assignment";
12
14
  @import "modules/exercise_results";
15
+ @import "modules/faqs";
13
16
  @import "modules/flash";
14
17
  @import "modules/gs-board";
15
18
  @import "modules/guide_corollary";
@@ -0,0 +1,12 @@
1
+ .mu-user-activity-indicator {
2
+ text-align: center;
3
+ border-radius: 10px;
4
+
5
+ &.jumbotron {
6
+ padding: 0.5em 0;
7
+ }
8
+ }
9
+
10
+ .mu-user-activity-selector {
11
+ padding-top: 15px;
12
+ }
@@ -0,0 +1,33 @@
1
+ .mu-certificate {
2
+ border: 1px solid $mu-color-dark-separator;
3
+ }
4
+
5
+ .mu-certificate-name {
6
+ margin-top: 0;
7
+ margin-bottom: 1em;
8
+ }
9
+
10
+ .mu-certificate-data {
11
+ margin-top: 30px;
12
+ }
13
+
14
+ .mu-certificate-buttons {
15
+ margin-bottom: 30px;
16
+ }
17
+
18
+ .mu-certificate-download-btn {
19
+ height: 35px;
20
+ padding: 0;
21
+ width: 157px;
22
+ border: none;
23
+ }
24
+ .mu-certificate-download-btn-icon {
25
+ border-right: 1px solid darken($mu-color-complementary, 10%);
26
+ padding: 8px 6px 9px 6px;
27
+ width: 35px;
28
+ }
29
+ .mu-certificate-download-btn-text {
30
+ display: inline-block;
31
+ width: 115px;
32
+ text-align: center;
33
+ }
@@ -287,9 +287,21 @@ summary.discussion-summary {
287
287
  }
288
288
  }
289
289
 
290
+ .discussion-new-message-buttons {
291
+ display: flex;
292
+ margin: 0 -10px;
293
+
294
+ .btn {
295
+ margin: 15px 10px;
296
+ }
297
+ }
298
+
299
+ .discussion-new-message-preview-button {
300
+ flex-grow: 0.2;
301
+ }
302
+
290
303
  .discussion-new-message-button {
291
- border-radius: 0;
292
- margin-top: 15px;
304
+ flex-grow: 1;
293
305
  }
294
306
 
295
307
  .discussion-message {
@@ -0,0 +1,84 @@
1
+ .mu-faqs-container {
2
+ position: relative;
3
+ display: table;
4
+ width: 100%;
5
+
6
+ .mu-faqs-content {
7
+ padding-top: 50px;
8
+
9
+ width: 100%;
10
+
11
+ @media (min-width: 768px) {
12
+ width: 75%;
13
+ float: right;
14
+ }
15
+
16
+ .mu-faqs-group {
17
+ padding: 32px;
18
+ box-shadow: 0 0.375em 2.8125em 0 #d2d5d9;
19
+ margin-bottom: 32px;
20
+
21
+ @media (max-width: 767px) {
22
+ &:not(.active) {
23
+ h3, p {
24
+ display: none
25
+ }
26
+ h2 {
27
+ margin-bottom: 0px;
28
+ }
29
+ }
30
+ }
31
+
32
+ h2 {
33
+ margin-top: 0;
34
+ margin-bottom: 20px;
35
+ }
36
+
37
+ h3 {
38
+ color: #1A94A3; // should be $brand-secondary
39
+ margin-top: 40px;
40
+ }
41
+
42
+ .mu-faqs-group-icon {
43
+ float: right;
44
+ margin-top: 10px;
45
+ cursor: pointer;
46
+ display: none;
47
+ @media (max-width: 767px) {
48
+ display: unset;
49
+ }
50
+ }
51
+ }
52
+ }
53
+
54
+ .mu-faqs-navbar {
55
+ top: 0;
56
+ position: sticky;
57
+ width: 25%;
58
+ padding-top: 50px;
59
+
60
+ ul {
61
+ border-left: 1px solid $mu-color-disabled;
62
+ list-style: none;
63
+ padding-left: 0px;
64
+ li {
65
+ padding: 8px 10px 8px 15px;
66
+ cursor: pointer;
67
+ &.active {
68
+ border-left: 3px solid transparent;
69
+ border-color: darken($brand-primary, 5%);
70
+ margin-left: -3px;
71
+ }
72
+ a {
73
+ color: $brand-primary;
74
+ &:hover {
75
+ text-decoration: none;
76
+ }
77
+ @media (min-width: $container-lg) {
78
+ font-size: 1.1em;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }