mumuki-laboratory 8.6.0 → 9.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) 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/upload.js +69 -14
  5. data/app/assets/javascripts/mumuki_laboratory/application/user.js +16 -5
  6. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +3 -0
  7. data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +3 -0
  8. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_certificate.scss +33 -0
  9. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_content_show.scss +15 -2
  10. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_faqs.scss +84 -0
  11. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_medal.scss +1 -1
  12. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_menu.scss +63 -0
  13. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +11 -0
  14. data/app/controllers/api/base_controller.rb +0 -1
  15. data/app/controllers/api/courses_controller.rb +1 -1
  16. data/app/controllers/api/organizations_controller.rb +5 -2
  17. data/app/controllers/api/roles_controller.rb +4 -0
  18. data/app/controllers/api/users_controller.rb +6 -1
  19. data/app/controllers/certificates_controller.rb +28 -0
  20. data/app/controllers/concerns/with_authorization.rb +1 -16
  21. data/app/controllers/concerns/with_certificate_render.rb +25 -0
  22. data/app/controllers/concerns/with_user_params.rb +4 -0
  23. data/app/controllers/discussions_messages_controller.rb +0 -1
  24. data/app/controllers/faqs_controller.rb +6 -0
  25. data/app/controllers/users_controller.rb +12 -5
  26. data/app/helpers/breadcrumbs_helper.rb +4 -0
  27. data/app/helpers/certificate_helper.rb +13 -0
  28. data/app/helpers/content_view_helper.rb +19 -0
  29. data/app/helpers/exercise_input_helper.rb +8 -17
  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/_progress_listing.html.erb +1 -1
  49. data/app/views/layouts/_user_menu.html.erb +17 -0
  50. data/app/views/layouts/application.html.erb +6 -1
  51. data/app/views/layouts/exercise_inputs/editors/_code.html.erb +2 -1
  52. data/app/views/layouts/exercise_inputs/editors/_upload.html.erb +11 -2
  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 +2 -2
  63. data/config/routes.rb +9 -0
  64. data/lib/mumuki/laboratory/locales/en.yml +13 -3
  65. data/lib/mumuki/laboratory/locales/es-CL.yml +13 -3
  66. data/lib/mumuki/laboratory/locales/es.yml +12 -2
  67. data/lib/mumuki/laboratory/locales/pt.yml +12 -2
  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 +18 -9
  77. data/spec/features/terms_flow_spec.rb +30 -0
  78. data/spec/helpers/application_helper_spec.rb +10 -0
  79. data/spec/helpers/certificate_helper_spec.rb +15 -0
  80. data/spec/javascripts/upload-spec.js +80 -0
  81. metadata +86 -14
  82. 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: 92a4fb878a7767d1fe4b760252213ae327d8e5ae82bab805065eddb85b3baa36
4
- data.tar.gz: e45d454449b183f1f4c200152a25f2df58ef385c1c07949e3fda7be94e6de57c
3
+ metadata.gz: 07b2e50b039758471cfb6e6ce92b5c72de56a3d6edbcc1ddbcdfd12422b51f34
4
+ data.tar.gz: 69b54d57063273a7f3dee32e42126eff821332dbe8acec8f8337f91f1b929b90
5
5
  SHA512:
6
- metadata.gz: 9113399868c37c29fc38521c88b1f4acd2477b6094469c97be54983eb46753245e79ea7d4a56cb641ade8746b05323ecdeef276321aeb70e19ceca123d232566
7
- data.tar.gz: 1f101adea0a26968fe86fc9f7d5084e4cd821ab9b17ca528762bb55573a0be5eeb98e2eba0e5affa83da30168f046c6ea1b7e7cd6654beed0eeb599ea0aaaa73
6
+ metadata.gz: 4acb2a84b7b526ceebc4be7daf104e9a9d614c5659ab853da9614b16b1d3caffdc42c2cfce3fcdb22ee69e364d1339405291644dcf8b8f213e3756daf29d11de
7
+ data.tar.gz: 83e3a2120935b9b87c004d11fbd599ffe3a92093ab2decc2f787a905a4d0c50edb964390275f06452883213d42c03c35832281ad5963340d8f41f5b691b1e23c
@@ -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
+ });
@@ -1,17 +1,72 @@
1
+ mumuki.upload = (() => {
2
+ class FileUploader {
3
+ constructor(file) {
4
+ this.file = file;
5
+ }
6
+
7
+ uploadFileIfValid() {
8
+ if (!this.file) return;
9
+
10
+ let maxFileSize = $('#mu-upload-input').attr("mu-upload-file-limit");
11
+ if (this.file.size > maxFileSize) {
12
+ return mumuki.upload.ui.showFileExceedsMaxSize();
13
+ }
14
+
15
+ mumuki.upload.ui.allowSubmissionFor(this.file.name);
16
+
17
+ const reader = new FileReader();
18
+ reader.onload = function (e) {
19
+ const contents = e.target.result;
20
+ $('#solution_content').html(contents);
21
+ };
22
+ reader.readAsText(this.file);
23
+
24
+ return reader;
25
+ }
26
+ }
27
+
28
+ class UI {
29
+ constructor() {
30
+ this.$uploadFileLimitExceeded = $('#mu-upload-file-limit-exceeded');
31
+ this.$uploadLabel = $('#mu-upload-label span');
32
+ this.$uploadLabelText = this.$uploadLabel.text();
33
+ this.$uploadIcon = $('#mu-upload-icon');
34
+ this.$btnSubmit = $('.btn-submit');
35
+ }
36
+
37
+ showFileExceedsMaxSize() {
38
+ this.$uploadFileLimitExceeded.removeClass('hidden');
39
+ this.$uploadLabel.text(this.$uploadLabelText);
40
+ this.$uploadIcon.addClass('fa-upload').removeClass('fa-file-alt');
41
+ this.$btnSubmit.addClass('disabled');
42
+ }
43
+
44
+ allowSubmissionFor(filename) {
45
+ this.$uploadFileLimitExceeded.addClass('hidden');
46
+ this.$uploadLabel.text(filename);
47
+ this.$uploadIcon.removeClass('fa-upload').addClass('fa-file-alt');
48
+ this.$btnSubmit.removeClass('disabled');
49
+ }
50
+ }
51
+
52
+ function _setUI() {
53
+ mumuki.upload.ui = new UI();
54
+ }
55
+
56
+ return {
57
+ FileUploader,
58
+ UI,
59
+
60
+ _setUI,
61
+
62
+ /** @type {UI} */
63
+ ui: null
64
+ };
65
+ })();
66
+
1
67
  mumuki.load(() => {
2
- $('#upload-input').change(function (evt) {
3
- var file = evt.target.files[0];
4
- if (!file) return;
5
-
6
- var reader = new FileReader();
7
- reader.onload = function (e) {
8
- var contents = e.target.result;
9
- $('#solution_content').html(contents);
10
- $(evt.target).val("");
11
- $('form.new_solution').submit();
12
- };
13
- reader.readAsText(file);
14
- return false;
68
+ $('#mu-upload-input').change(function (evt) {
69
+ if (!mumuki.upload.ui) mumuki.upload._setUI();
70
+ return new mumuki.upload.FileUploader(evt.target.files[0]).uploadFileIfValid();
15
71
  });
16
72
  });
17
-
@@ -1,9 +1,20 @@
1
1
  mumuki.load(() => {
2
- var hash = document.location.hash;
3
- if (hash) {
4
- $(".nav-tabs a[data-target='" + hash + "']").tab('show');
2
+ const $userMenuHeader = $('.mu-user-menu-header');
3
+ let onUserProfile = document.querySelector('.mu-profile-info') !== null;
4
+
5
+ $userMenuHeader.click(() => {
6
+ $('.mu-user-menu-items').toggleClass('hidden-sm-screen');
7
+ $('#mu-user-menu-header-icon').toggleClass('fa-chevron-up fa-chevron-down');
8
+ });
9
+
10
+ if (onUserProfile) {
11
+ $userMenuHeader.click();
5
12
  }
6
- $('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
7
- window.location.hash = $(e.target).attr('data-target');
13
+
14
+ $('.mu-user-menu-item .active').click((e) => {
15
+ if (onUserProfile) {
16
+ e.preventDefault();
17
+ $userMenuHeader.click();
18
+ }
8
19
  });
9
20
  });
@@ -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 p {
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
+ }