mumuki-laboratory 8.6.1 → 9.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) 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/faqs.js +90 -0
  4. data/app/assets/javascripts/mumuki_laboratory/application/organization.js +32 -0
  5. data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +1 -1
  6. data/app/assets/javascripts/mumuki_laboratory/application/user.js +49 -5
  7. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +3 -0
  8. data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +3 -0
  9. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_certificate.scss +33 -0
  10. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_content_show.scss +15 -2
  11. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_faqs.scss +84 -0
  12. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_medal.scss +1 -1
  13. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_menu.scss +63 -0
  14. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +11 -0
  15. data/app/controllers/api/base_controller.rb +0 -1
  16. data/app/controllers/api/courses_controller.rb +1 -1
  17. data/app/controllers/api/organizations_controller.rb +5 -2
  18. data/app/controllers/api/roles_controller.rb +4 -0
  19. data/app/controllers/api/users_controller.rb +6 -1
  20. data/app/controllers/certificates_controller.rb +28 -0
  21. data/app/controllers/concerns/with_authorization.rb +1 -16
  22. data/app/controllers/concerns/with_certificate_render.rb +25 -0
  23. data/app/controllers/concerns/with_user_params.rb +4 -0
  24. data/app/controllers/discussions_messages_controller.rb +0 -1
  25. data/app/controllers/faqs_controller.rb +6 -0
  26. data/app/controllers/users_controller.rb +12 -5
  27. data/app/helpers/breadcrumbs_helper.rb +4 -0
  28. data/app/helpers/certificate_helper.rb +13 -0
  29. data/app/helpers/content_view_helper.rb +19 -0
  30. data/app/helpers/links_helper.rb +11 -3
  31. data/app/helpers/menu_bar_helper.rb +15 -11
  32. data/app/helpers/user_menu_helper.rb +36 -0
  33. data/app/mailers/application_mailer.rb +0 -1
  34. data/app/mailers/user_mailer.rb +9 -0
  35. data/app/views/certificates/_certificate.html.erb +44 -0
  36. data/app/views/certificates/_download.html.erb +20 -0
  37. data/app/views/certificates/verify.html.erb +40 -0
  38. data/app/views/chapters/show.html.erb +15 -14
  39. data/app/views/complements/show.html.erb +1 -1
  40. data/app/views/exams/show.html.erb +1 -1
  41. data/app/views/{layouts → exercises}/_exercise_skipped.html.erb +0 -0
  42. data/app/views/exercises/_exercise_title_icons.html.erb +4 -0
  43. data/app/views/exercises/show.html.erb +4 -7
  44. data/app/views/faqs/index.html.erb +20 -0
  45. data/app/views/{layouts → guides}/_guide.html.erb +0 -0
  46. data/app/views/guides/_guide_container.html.erb +24 -0
  47. data/app/views/{layouts → guides}/_guide_title_icons.html.erb +1 -3
  48. data/app/views/layouts/_main.html.erb +4 -0
  49. data/app/views/layouts/_progress_listing.html.erb +1 -1
  50. data/app/views/layouts/_user_menu.html.erb +17 -0
  51. data/app/views/layouts/application.html.erb +6 -1
  52. data/app/views/layouts/exercise_inputs/editors/_code.html.erb +2 -1
  53. data/app/views/lessons/show.html.erb +1 -1
  54. data/app/views/user_mailer/certificate.html.erb +339 -0
  55. data/app/views/user_mailer/certificate.text.erb +10 -0
  56. data/app/views/users/_user_form.html.erb +10 -8
  57. data/app/views/users/certificates.html.erb +32 -0
  58. data/app/views/users/discussions.html.erb +28 -0
  59. data/app/views/users/edit.html.erb +1 -1
  60. data/app/views/users/messages.html.erb +27 -0
  61. data/app/views/users/show.html.erb +4 -51
  62. data/app/views/users/terms.html.erb +1 -1
  63. data/config/routes.rb +9 -0
  64. data/lib/mumuki/laboratory/locales/en.yml +10 -1
  65. data/lib/mumuki/laboratory/locales/es-CL.yml +10 -1
  66. data/lib/mumuki/laboratory/locales/es.yml +10 -1
  67. data/lib/mumuki/laboratory/locales/pt.yml +10 -1
  68. data/lib/mumuki/laboratory/version.rb +1 -1
  69. data/spec/controllers/certificates_controller_spec.rb +15 -0
  70. data/spec/controllers/organizations_api_controller_spec.rb +16 -9
  71. data/spec/dummy/db/schema.rb +25 -1
  72. data/spec/features/certificate_programs_flow_spec.rb +17 -0
  73. data/spec/features/exercise_flow_spec.rb +3 -3
  74. data/spec/features/login_flow_spec.rb +1 -1
  75. data/spec/features/menu_bar_spec.rb +44 -24
  76. data/spec/features/profile_flow_spec.rb +17 -7
  77. data/spec/helpers/application_helper_spec.rb +10 -0
  78. data/spec/helpers/certificate_helper_spec.rb +15 -0
  79. metadata +81 -10
  80. data/app/views/layouts/_guide_container.html.erb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 824e346e9d3113f3b3d48c8ed7e23c846e26a54fb5ed7e4c4bb5a9307323b4d7
4
- data.tar.gz: e28b9bdf65007abda370a36b760adeaf7989ab9e4c94c52ebaa09bcd3f14fb79
3
+ metadata.gz: c79de66ab1c8248e5715cd1e54ac8e4b1e426fb26bc0a69b35539ba19eb954da
4
+ data.tar.gz: 39cbfb28e86a6ae64f5a1164731d472ca65be3bec82d9f1ed6f159273512b078
5
5
  SHA512:
6
- metadata.gz: 46a32c31bb80eca3fa50fc45c37875a36894cf3fbc2192f339c138763afeac44a811ab336650460a7e7f150323601d92cab90c91e967668916462d21026eb72a
7
- data.tar.gz: c9ecc5bd9523a72129d3914317fa29c596038b99f3733de72fc71c27b5c1be3295d9f79ddff39d3cf39c8cfb22bd873581442c4c9121680cdd68901990a11b54
6
+ metadata.gz: ed9430f79c8f92f7b02264aa84f7dc757a7ff05915fcdd17e93a5fe4b7aaac5cfd0d87fadec66ce0d4ac204cd270f08fafc1550a986bd367314f5e7130c360d4
7
+ data.tar.gz: 8669d687ca7f70178cab77c25f698eef49a58eb74957ed274c73fe6fdf0c6f9139c5963f5c57b08a92ed874a97c6b648030c1be87cd34b107cb831db156e0113
@@ -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
+ });
@@ -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('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
  });
@@ -122,6 +122,9 @@ hr {
122
122
 
123
123
  /* TODO: move to mumuki-styles */
124
124
  .mu-inline-block-left {
125
+ display: flex;
126
+ align-items: center;
127
+
125
128
  margin-left: 15px;
126
129
  }
127
130
 
@@ -1,6 +1,7 @@
1
1
  @import "modules/avatar";
2
2
  @import "modules/book_header";
3
3
  @import "modules/breadcrumb";
4
+ @import "modules/certificate";
4
5
  @import "modules/checkboxes";
5
6
  @import "modules/console";
6
7
  @import "modules/content_show";
@@ -10,6 +11,7 @@
10
11
  @import "modules/editor";
11
12
  @import "modules/exercise_assignment";
12
13
  @import "modules/exercise_results";
14
+ @import "modules/faqs";
13
15
  @import "modules/flash";
14
16
  @import "modules/gs-board";
15
17
  @import "modules/guide_corollary";
@@ -27,4 +29,5 @@
27
29
  @import "modules/terms";
28
30
  @import "modules/timer";
29
31
  @import "modules/upload";
32
+ @import "modules/user_menu";
30
33
  @import "modules/user_profile";
@@ -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
+ }
@@ -1,3 +1,16 @@
1
- .chapter-description {
2
- display: inline-block;
1
+ .mu-chapter-description p {
2
+ display: inline-block
3
+ }
4
+
5
+ .mu-content-title-icons {
6
+ display: flex;
7
+ align-items: center;
8
+
9
+ font-size: 150%;
10
+ margin-left: 15px;
11
+ margin-right: 15px;
12
+
13
+ i {
14
+ margin-left: 5px;
15
+ }
3
16
  }
@@ -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
+ }
@@ -28,7 +28,7 @@
28
28
  left: 20px;
29
29
  top: 17px;
30
30
 
31
- margin-right: 30px;
31
+ margin-right: 40px;
32
32
  margin-bottom: 15px;
33
33
  }
34
34
 
@@ -0,0 +1,63 @@
1
+ .mu-user-menu {
2
+ display: flex;
3
+ margin-top: 25px;
4
+ }
5
+
6
+ .mu-user-menu-content {
7
+ flex-grow: 1;
8
+ }
9
+
10
+ .mu-user-menu-header {
11
+ font-size: 15px;
12
+ color: $mu-color-disabled;
13
+ text-transform: uppercase;
14
+ padding-left: 2px;
15
+ cursor: pointer;
16
+
17
+ @media only screen and (min-width: $screen-md-min) {
18
+ padding-left: 15px;
19
+ cursor: auto;
20
+
21
+ i {
22
+ display: none;
23
+ }
24
+
25
+ span {
26
+ padding-left: 0px;
27
+ }
28
+ }
29
+ }
30
+
31
+ .mu-user-menu-items {
32
+ margin-top: 30px;
33
+
34
+ &.hidden-sm-screen {
35
+ @media only screen and (max-width: $screen-sm-max) {
36
+ display: none;
37
+ }
38
+ }
39
+ }
40
+
41
+ .mu-user-menu-item {
42
+ font-size: 17px;
43
+ margin-bottom: 5px;
44
+
45
+ a {
46
+ color: $brand-primary;
47
+ &.active {
48
+ font-weight: bold;
49
+ }
50
+ }
51
+ }
52
+
53
+ .mu-user-menu-divider {
54
+ &.vertical {
55
+ border-left: 2px solid $mu-color-separator;
56
+ }
57
+
58
+ &.horizontal {
59
+ border-top: 2px solid $mu-color-separator;
60
+
61
+ margin: 25px 0;
62
+ }
63
+ }