open_fresk 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +64 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +248 -0
- data/MIT-LICENSE +20 -0
- data/README.md +130 -0
- data/Rakefile +8 -0
- data/app/.DS_Store +0 -0
- data/app/assets/.DS_Store +0 -0
- data/app/assets/config/manifest.js +20 -0
- data/app/assets/images/open_fresk/.keep +0 -0
- data/app/assets/images/open_fresk/favicon.png +0 -0
- data/app/assets/images/open_fresk/logos/logo.png +0 -0
- data/app/assets/stylesheets/open_fresk/application.scss +90 -0
- data/app/assets/stylesheets/open_fresk/components/_accordion.scss +3 -0
- data/app/assets/stylesheets/open_fresk/components/_btn.scss +25 -0
- data/app/assets/stylesheets/open_fresk/components/_btn_toggle.scss +16 -0
- data/app/assets/stylesheets/open_fresk/components/_card.scss +6 -0
- data/app/assets/stylesheets/open_fresk/components/_checkout.scss +142 -0
- data/app/assets/stylesheets/open_fresk/components/_cursors.scss +35 -0
- data/app/assets/stylesheets/open_fresk/components/_dropdown_toggle.scss +9 -0
- data/app/assets/stylesheets/open_fresk/components/_form.scss +22 -0
- data/app/assets/stylesheets/open_fresk/components/_google_maps_autocomplete.scss +3 -0
- data/app/assets/stylesheets/open_fresk/components/_hamburger_button.scss +41 -0
- data/app/assets/stylesheets/open_fresk/components/_header.scss +57 -0
- data/app/assets/stylesheets/open_fresk/components/_iframe.scss +26 -0
- data/app/assets/stylesheets/open_fresk/components/_index.scss +22 -0
- data/app/assets/stylesheets/open_fresk/components/_nav_pills.scss +26 -0
- data/app/assets/stylesheets/open_fresk/components/_nps_progress_bar.scss +97 -0
- data/app/assets/stylesheets/open_fresk/components/_pagination.scss +11 -0
- data/app/assets/stylesheets/open_fresk/components/_progress_bar.scss +17 -0
- data/app/assets/stylesheets/open_fresk/components/_radio_button.scss +25 -0
- data/app/assets/stylesheets/open_fresk/components/_range.scss +253 -0
- data/app/assets/stylesheets/open_fresk/components/_select_input.scss +9 -0
- data/app/assets/stylesheets/open_fresk/components/_slider.scss +61 -0
- data/app/assets/stylesheets/open_fresk/components/_slim_select.scss +31 -0
- data/app/assets/stylesheets/open_fresk/components/_timeline.scss +165 -0
- data/app/assets/stylesheets/open_fresk/components/_tooltip.scss +20 -0
- data/app/assets/stylesheets/open_fresk/components/_transformation.scss +4 -0
- data/app/assets/stylesheets/open_fresk/config/_belts.scss +38 -0
- data/app/assets/stylesheets/open_fresk/config/_bg.scss +6 -0
- data/app/assets/stylesheets/open_fresk/config/_border.scss +15 -0
- data/app/assets/stylesheets/open_fresk/config/_colors.scss +42 -0
- data/app/assets/stylesheets/open_fresk/config/_index.scss +6 -0
- data/app/assets/stylesheets/open_fresk/config/_text.scss +24 -0
- data/app/assets/stylesheets/open_fresk/config/_typography.scss +26 -0
- data/app/assets/stylesheets/open_fresk/external_libraries/_actiontext.scss +30 -0
- data/app/assets/stylesheets/open_fresk/external_libraries/_slimselect.min.scss +1 -0
- data/app/assets/stylesheets/open_fresk/external_libraries/index.scss +2 -0
- data/app/assets/stylesheets/open_fresk/pages/_index.scss +1 -0
- data/app/assets/stylesheets/open_fresk/pages/_signin.scss +10 -0
- data/app/assets/stylesheets-original/open_fresk/application.css +90 -0
- data/app/controllers/.DS_Store +0 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/concerns/open_fresk/authentication.rb +18 -0
- data/app/controllers/open_fresk/application_controller.rb +5 -0
- data/app/controllers/open_fresk/sessions_controller.rb +38 -0
- data/app/controllers/open_fresk/training_sessions_controller.rb +17 -0
- data/app/extensions/open_fresk/core_extensions/string.rb +13 -0
- data/app/helpers/header_helper.rb +2 -0
- data/app/helpers/open_fresk/application_helper.rb +18 -0
- data/app/helpers/plateform_access/rights_helper.rb +15 -0
- data/app/javascript/manifest.json +15 -0
- data/app/javascript/open_fresk/application.js +7 -0
- data/app/javascript/open_fresk/controllers/hello_controller.js +7 -0
- data/app/jobs/open_fresk/application_job.rb +4 -0
- data/app/mailers/open_fresk/application_mailer.rb +6 -0
- data/app/models/.DS_Store +0 -0
- data/app/models/concerns/.keep +0 -0
- data/app/models/open_fresk/application_record.rb +10 -0
- data/app/models/open_fresk/training_session.rb +9 -0
- data/app/models/open_fresk/user.rb +9 -0
- data/app/services/open_fresk/extensions/string_enum.rb +201 -0
- data/app/views/layouts/header/_hamburger.html.erb +7 -0
- data/app/views/layouts/header/_logo.html.erb +5 -0
- data/app/views/layouts/open_fresk/_alert.html.erb +0 -0
- data/app/views/layouts/open_fresk/_footer.html.erb +0 -0
- data/app/views/layouts/open_fresk/_header.html.erb +12 -0
- data/app/views/layouts/open_fresk/_include.html.erb +24 -0
- data/app/views/layouts/open_fresk/_meta.html.erb +10 -0
- data/app/views/layouts/open_fresk/application.html.erb +23 -0
- data/app/views/open_fresk/sessions/_login.html.erb +16 -0
- data/app/views/open_fresk/sessions/new.html.erb +8 -0
- data/app/views/open_fresk/training_sessions/_card.html.erb +0 -0
- data/app/views/open_fresk/training_sessions/index.html.erb +22 -0
- data/bin/rails +14 -0
- data/config/importmap.rb +6 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/fr.yml +15 -0
- data/config/routes.rb +8 -0
- data/lib/.DS_Store +0 -0
- data/lib/open_fresk/engine.rb +93 -0
- data/lib/open_fresk/version.rb +3 -0
- data/lib/open_fresk.rb +6 -0
- data/lib/tasks/open_fresk_tasks.rake +4 -0
- data/open_fresk.gemspec +29 -0
- metadata +250 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
/*
|
2
|
+
* Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and
|
3
|
+
* the trix-editor content (whether displayed or under editing). Feel free to incorporate this
|
4
|
+
* inclusion directly in any other asset bundle and remove this file.
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
|
8
|
+
/*
|
9
|
+
* We need to override trix.css’s image gallery styles to accommodate the
|
10
|
+
* <action-text-attachment> element we wrap around attachments. Otherwise,
|
11
|
+
* images in galleries will be squished by the max-width: 33%; rule.
|
12
|
+
*/
|
13
|
+
.trix-content .attachment-gallery > action-text-attachment,
|
14
|
+
.trix-content .attachment-gallery > .attachment {
|
15
|
+
flex: 1 0 33%;
|
16
|
+
padding: 0 0.5em;
|
17
|
+
max-width: 33%;
|
18
|
+
}
|
19
|
+
|
20
|
+
.trix-content .attachment-gallery.attachment-gallery--2 > action-text-attachment,
|
21
|
+
.trix-content .attachment-gallery.attachment-gallery--2 > .attachment, .trix-content .attachment-gallery.attachment-gallery--4 > action-text-attachment,
|
22
|
+
.trix-content .attachment-gallery.attachment-gallery--4 > .attachment {
|
23
|
+
flex-basis: 50%;
|
24
|
+
max-width: 50%;
|
25
|
+
}
|
26
|
+
|
27
|
+
.trix-content action-text-attachment .attachment {
|
28
|
+
padding: 0 !important;
|
29
|
+
max-width: 100% !important;
|
30
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
:root{--ss-primary-color:#5897fb;--ss-bg-color:#ffffff;--ss-font-color:#4d4d4d;--ss-font-placeholder-color:#8d8d8d;--ss-disabled-color:#dcdee2;--ss-border-color:#dcdee2;--ss-highlight-color:#fffb8c;--ss-success-color:#00b755;--ss-error-color:#dc3545;--ss-main-height:30px;--ss-content-height:300px;--ss-spacing-l:7px;--ss-spacing-m:5px;--ss-spacing-s:3px;--ss-animation-timing:0.2s;--ss-border-radius:4px}@keyframes ss-valueIn{0%{transform:scale(0);opacity:0}100%{transform:scale(1);opacity:1}}@keyframes ss-valueOut{0%{transform:scale(1);opacity:1}100%{transform:scale(0);opacity:0}}.ss-hide{display:none!important}.ss-main{display:flex;flex-direction:row;position:relative;user-select:none;color:var(--ss-font-color);min-height:var(--ss-main-height);width:100%;padding:var(--ss-spacing-s);cursor:pointer;border:1px solid var(--ss-border-color);border-radius:var(--ss-border-radius);background-color:var(--ss-bg-color);outline:0;box-sizing:border-box;transition:background-color var(--ss-animation-timing);overflow:hidden}.ss-main:focus{box-shadow:0 0 5px var(--ss-primary-color)}.ss-main.ss-disabled{background-color:var(--ss-disabled-color);cursor:not-allowed}.ss-main.ss-disabled .ss-values .ss-disabled{color:var(--ss-font-color)}.ss-main.ss-disabled .ss-values .ss-value .ss-value-delete{cursor:not-allowed}.ss-main.ss-open-above{border-top-left-radius:0;border-top-right-radius:0}.ss-main.ss-open-below{border-bottom-left-radius:0;border-bottom-right-radius:0}.ss-main .ss-values{display:inline-flex;flex-wrap:wrap;gap:var(--ss-spacing-m);flex:1 1 100%}.ss-main .ss-values .ss-placeholder{display:flex;padding:var(--ss-spacing-s) var(--ss-spacing-m) var(--ss-spacing-s) var(--ss-spacing-m);margin:auto 0 auto 0;line-height:1em;align-items:center;width:100%;color:var(--ss-font-placeholder-color);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ss-main .ss-values .ss-max{display:flex;user-select:none;align-items:center;width:fit-content;font-size:12px;color:var(--ss-bg-color);line-height:1;padding:var(--ss-spacing-s) var(--ss-spacing-m);background-color:var(--ss-primary-color);border-radius:var(--ss-border-radius)}.ss-main .ss-values .ss-single{display:flex;margin:auto 0 auto var(--ss-spacing-s)}.ss-main .ss-values .ss-value{display:flex;user-select:none;align-items:center;width:fit-content;background-color:var(--ss-primary-color);border-radius:var(--ss-border-radius);animation-name:ss-valueIn;animation-duration:var(--ss-animation-timing);animation-timing-function:ease-out;animation-fill-mode:both}.ss-main .ss-values .ss-value.ss-value-out{animation-name:ss-valueOut;animation-duration:var(--ss-animation-timing);animation-timing-function:ease-out}.ss-main .ss-values .ss-value .ss-value-text{font-size:12px;color:var(--ss-bg-color);line-height:1;padding:var(--ss-spacing-s) var(--ss-spacing-m)}.ss-main .ss-values .ss-value .ss-value-delete{display:flex;align-items:center;height:var(--ss-spacing-l);width:var(--ss-spacing-l);padding:var(--ss-spacing-s) var(--ss-spacing-m);cursor:pointer;border-left:solid 1px var(--ss-bg-color);box-sizing:content-box}.ss-main .ss-values .ss-value .ss-value-delete svg{height:var(--ss-spacing-l);width:var(--ss-spacing-l)}.ss-main .ss-values .ss-value .ss-value-delete svg path{fill:none;stroke:var(--ss-bg-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round}.ss-main .ss-deselect{display:flex;align-self:center;justify-content:flex-end;flex:0 1 auto;width:8px;height:8px;margin:0 var(--ss-spacing-m) 0 var(--ss-spacing-m)}.ss-main .ss-deselect svg{width:8px;height:8px}.ss-main .ss-deselect svg path{fill:none;stroke:var(--ss-font-color);stroke-width:20;stroke-linecap:round;stroke-linejoin:round}.ss-main .ss-arrow{display:flex;align-items:center;justify-content:flex-end;flex:0 1 auto;width:12px;height:12px;margin:auto var(--ss-spacing-m) auto var(--ss-spacing-m)}.ss-main .ss-arrow path{fill:none;stroke:var(--ss-font-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round;transition-timing-function:ease-out;transition:var(--ss-animation-timing)}.ss-content{position:absolute;display:flex;height:auto;flex-direction:column;width:auto;max-height:var(--ss-content-height);box-sizing:border-box;border:solid 1px var(--ss-border-color);background-color:var(--ss-bg-color);transition:transform var(--ss-animation-timing),opacity var(--ss-animation-timing);opacity:0;transform:scaleY(0);transform-origin:center top;overflow:hidden;z-index:10000}.ss-content.ss-relative{position:relative;height:100%}.ss-content.ss-open-above{flex-direction:column-reverse;opacity:1;transform:scaleY(1);transform-origin:center bottom;border-top-left-radius:var(--ss-border-radius);border-top-right-radius:var(--ss-border-radius)}.ss-content.ss-open-below{opacity:1;transform:scaleY(1);transform-origin:center top;border-bottom-left-radius:var(--ss-border-radius);border-bottom-right-radius:var(--ss-border-radius)}.ss-content .ss-search{flex:0 1 auto;display:flex;flex-direction:row;padding:var(--ss-spacing-l) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l)}.ss-content .ss-search input{display:inline-flex;font-size:inherit;line-height:inherit;flex:1 1 auto;width:100%;min-width:0;padding:var(--ss-spacing-m) var(--ss-spacing-l);margin:0;border:1px solid var(--ss-border-color);border-radius:var(--ss-border-radius);background-color:var(--ss-bg-color);outline:0;text-align:left;box-sizing:border-box}.ss-content .ss-search input::placeholder{color:var(--ss-font-placeholder-color);vertical-align:middle}.ss-content .ss-search input:focus{box-shadow:0 0 5px var(--ss-primary-color)}.ss-content .ss-search .ss-addable{display:inline-flex;justify-content:center;align-items:center;cursor:pointer;flex:0 0 auto;height:auto;margin:0 0 0 var(--ss-spacing-m);border:1px solid var(--ss-border-color);border-radius:var(--ss-border-radius)}.ss-content .ss-search .ss-addable svg{display:flex;align-items:center;justify-content:flex-end;flex:0 1 auto;width:12px;height:12px;margin:auto var(--ss-spacing-m) auto var(--ss-spacing-m)}.ss-content .ss-search .ss-addable svg path{fill:none;stroke:var(--ss-font-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round}.ss-content .ss-list{flex:1 1 auto;height:auto;overflow-x:hidden;overflow-y:auto}.ss-content .ss-list .ss-error{color:var(--ss-error-color);padding:var(--ss-spacing-l)}.ss-content .ss-list .ss-searching{color:var(--ss-font-color);padding:var(--ss-spacing-l)}.ss-content .ss-list .ss-optgroup.ss-close .ss-option{display:none!important}.ss-content .ss-list .ss-optgroup .ss-optgroup-label{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:var(--ss-spacing-m) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-label-text{flex:1 1 auto;font-weight:700;color:var(--ss-font-color)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label:has(.ss-arrow){cursor:pointer}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions{flex:0 1 auto;display:flex;flex-direction:row;align-items:center;justify-content:center;gap:var(--ss-spacing-m)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall{flex:0 0 auto;display:flex;flex-direction:row;cursor:pointer}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall:hover{opacity:.5}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall.ss-selected svg path{stroke:var(--ss-error-color)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall span{flex:0 1 auto;display:flex;align-items:center;justify-content:center;font-size:60%;text-align:center;padding:0 var(--ss-spacing-s) 0 0}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg{flex:0 1 auto;width:13px;height:13px}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg path{fill:none;stroke:var(--ss-success-color);stroke-linecap:round;stroke-linejoin:round}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg:first-child{stroke-width:5}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg:last-child{stroke-width:11}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-closable{flex:0 1 auto;display:flex;flex-direction:row;cursor:pointer}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-closable .ss-arrow{flex:1 1 auto;width:10px;height:10px}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-closable .ss-arrow path{fill:none;stroke:var(--ss-font-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round;transition-timing-function:ease-out;transition:var(--ss-animation-timing)}.ss-content .ss-list .ss-optgroup .ss-option{padding:var(--ss-spacing-s) var(--ss-spacing-s) var(--ss-spacing-s) calc(var(--ss-spacing-l)*3)}.ss-content .ss-list .ss-option{display:flex;padding:var(--ss-spacing-m) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l);color:var(--ss-font-color);cursor:pointer;user-select:none}.ss-content .ss-list .ss-option:hover{color:var(--ss-bg-color);background-color:var(--ss-primary-color)}.ss-content .ss-list .ss-option.ss-highlighted,.ss-content .ss-list .ss-option:not(.ss-disabled).ss-selected{color:var(--ss-bg-color);background-color:var(--ss-primary-color)}.ss-content .ss-list .ss-option.ss-disabled{cursor:not-allowed;background-color:var(--ss-disabled-color)}.ss-content .ss-list .ss-option.ss-disabled:hover{color:var(--ss-font-color)}.ss-content .ss-list .ss-option .ss-search-highlight{background-color:var(--ss-highlight-color)}
|
@@ -0,0 +1 @@
|
|
1
|
+
@import "signin";
|
@@ -0,0 +1,90 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
|
6
|
+
* vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*/
|
14
|
+
|
15
|
+
label.required:after {
|
16
|
+
content: "*";
|
17
|
+
}
|
18
|
+
|
19
|
+
// Main stylesheet
|
20
|
+
|
21
|
+
// CSS partials
|
22
|
+
@import "config/index";
|
23
|
+
@import "external_libraries/index";
|
24
|
+
@import "components/index";
|
25
|
+
@import "pages/index";
|
26
|
+
@import "font_awesome5_webfont";
|
27
|
+
$fa-font-path: "@fortawesome/fontawesome-free/webfonts";
|
28
|
+
@import "@fortawesome/fontawesome-free/scss/fontawesome";
|
29
|
+
@import "@fortawesome/fontawesome-free/scss/brands";
|
30
|
+
@import "@fortawesome/fontawesome-free/scss/solid";
|
31
|
+
@import "@fortawesome/fontawesome-free/scss/regular";
|
32
|
+
@import "@fortawesome/fontawesome-free/scss/v4-shims";
|
33
|
+
@import "bootstrap";
|
34
|
+
|
35
|
+
// External libraries
|
36
|
+
body,
|
37
|
+
html {
|
38
|
+
width: 100%;
|
39
|
+
height: 100%;
|
40
|
+
}
|
41
|
+
|
42
|
+
* {
|
43
|
+
font-family: "Roboto", sans-serif;
|
44
|
+
}
|
45
|
+
|
46
|
+
body {
|
47
|
+
display: flex !important;
|
48
|
+
align-items: center;
|
49
|
+
padding-top: 0px;
|
50
|
+
padding-bottom: 0px;
|
51
|
+
font-weight: 400 !important;
|
52
|
+
margin-bottom: 20px !important;
|
53
|
+
margin-top: 20px !important;
|
54
|
+
}
|
55
|
+
|
56
|
+
img {
|
57
|
+
aspect-ratio: attr(width) / attr(height);
|
58
|
+
}
|
59
|
+
|
60
|
+
p.copyright {
|
61
|
+
margin: 15px 0 0;
|
62
|
+
}
|
63
|
+
|
64
|
+
.rounded-4 {
|
65
|
+
border-radius: 8px;
|
66
|
+
}
|
67
|
+
.rounded-5 {
|
68
|
+
border-radius: 10px;
|
69
|
+
}
|
70
|
+
|
71
|
+
.square-50 {
|
72
|
+
width: 50px;
|
73
|
+
height: 50px;
|
74
|
+
display: flex;
|
75
|
+
flex-direction: column;
|
76
|
+
justify-content: center;
|
77
|
+
}
|
78
|
+
|
79
|
+
.nav-item.dropdown .dropdown-item:active {
|
80
|
+
background-color: transparent !important;
|
81
|
+
}
|
82
|
+
|
83
|
+
.list-style-none {
|
84
|
+
list-style-type: none;
|
85
|
+
}
|
86
|
+
|
87
|
+
input[type="radio"] {
|
88
|
+
width: 16px;
|
89
|
+
height: 16px;
|
90
|
+
}
|
Binary file
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module OpenFresk::Authentication
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
helper_method :current_user
|
6
|
+
before_action :authenticate_user!
|
7
|
+
end
|
8
|
+
|
9
|
+
def current_user
|
10
|
+
@current_user ||= ::User.find_by(id: session[:user_id])
|
11
|
+
end
|
12
|
+
|
13
|
+
def authenticate_user!
|
14
|
+
return if current_user
|
15
|
+
session[:forwarding_url] = request.fullpath if request.get?
|
16
|
+
redirect_to new_session_path, alert: t("please_log_in")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module OpenFresk
|
2
|
+
class SessionsController < ApplicationController
|
3
|
+
skip_before_action :authenticate_user!
|
4
|
+
|
5
|
+
def new
|
6
|
+
end
|
7
|
+
|
8
|
+
def create
|
9
|
+
user = ::User.where(email: params[:email]&.downcase).first
|
10
|
+
if user&.authenticate(params[:password])
|
11
|
+
session[:user_id] = user.id
|
12
|
+
|
13
|
+
# Allow host app to add custom behavior
|
14
|
+
after_sign_in_hook(user)
|
15
|
+
|
16
|
+
redirect_to redirection_url(user)
|
17
|
+
else
|
18
|
+
@alert = t("sessions.invalid_credentials")
|
19
|
+
respond_to do |format|
|
20
|
+
format.html { redirect_to open_fresk.new_session_path, alert: @alert }
|
21
|
+
format.turbo_stream do
|
22
|
+
render turbo_stream: turbo_stream.prepend("signin", partial: "wrong_credentials", locals: {alert: @alert})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def redirection_url(user)
|
31
|
+
root_url
|
32
|
+
end
|
33
|
+
|
34
|
+
def after_sign_in_hook(user)
|
35
|
+
# No-op by default
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OpenFresk
|
2
|
+
class TrainingSessionsController < ApplicationController
|
3
|
+
def index
|
4
|
+
end
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def sessions_lists
|
9
|
+
public_opportunities
|
10
|
+
end
|
11
|
+
|
12
|
+
def public_opportunities
|
13
|
+
training_sessions = TrainingSession.futur
|
14
|
+
@my_training_sessions = training_sessions.my_sessions(current_user)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PlateformAccess
|
2
|
+
module RightsHelper
|
3
|
+
def current_user_rights_animator_and_up?
|
4
|
+
current_user&.super_admin? || current_user&.administrator? || current_user&.organiser? || current_user&.animator?
|
5
|
+
end
|
6
|
+
|
7
|
+
def current_user_is_admin?
|
8
|
+
current_user&.super_admin? || current_user&.administrator?
|
9
|
+
end
|
10
|
+
|
11
|
+
def current_user_can_create_general_public_sessions?
|
12
|
+
current_user&.super_admin? || current_user&.administrator? || current_user&.organiser?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"name": "OpenFresk",
|
3
|
+
"short_name": "Fresk",
|
4
|
+
"start_url": "/",
|
5
|
+
"display": "standalone",
|
6
|
+
"background_color": "#ffffff",
|
7
|
+
"theme_color": "#ffffff",
|
8
|
+
"icons": [
|
9
|
+
{
|
10
|
+
"src": "/assets/open_fresk/favicon.png",
|
11
|
+
"sizes": "192x192",
|
12
|
+
"type": "image/png"
|
13
|
+
}
|
14
|
+
]
|
15
|
+
}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { Application } from "@hotwired/stimulus";
|
2
|
+
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading";
|
3
|
+
|
4
|
+
const application = Application.start();
|
5
|
+
eagerLoadControllersFrom("open_fresk/controllers", application);
|
6
|
+
|
7
|
+
console.log("🔌 open_fresk.js loaded");
|
Binary file
|
File without changes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module OpenFresk
|
2
|
+
class TrainingSession < ApplicationRecord
|
3
|
+
self.table_name = 'training_sessions'
|
4
|
+
|
5
|
+
scope :futur, -> { where("end_time >= ?", DateTime.current.beginning_of_day).order(date: :asc) }
|
6
|
+
scope :organized_by, ->(user) { where(created_by_user_id: user&.id) }
|
7
|
+
scope :my_sessions, ->(user) { where(id: organized_by(user)) }
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenFresk
|
4
|
+
module Extensions
|
5
|
+
module StringEnum
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# string_enum allow a developer to define a set of named constants
|
10
|
+
#
|
11
|
+
# ==== Examples
|
12
|
+
#
|
13
|
+
# class User
|
14
|
+
# include StringEnum
|
15
|
+
#
|
16
|
+
# string_enum role: %i[employee admin manager]
|
17
|
+
#
|
18
|
+
# # automaticaly include validation
|
19
|
+
# # validates(:role, inclusion: { in: ['EMPLOYEE', 'ADMIN', 'MANAGER'] }, allow_nil: true)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# define all methods bellow:
|
23
|
+
#
|
24
|
+
# user.employee?
|
25
|
+
# user.admin?
|
26
|
+
# user.manager?
|
27
|
+
#
|
28
|
+
# user.employee!
|
29
|
+
# user.admin!
|
30
|
+
# user.manager!
|
31
|
+
#
|
32
|
+
# User::Employee # => 'EMPLOYEE'
|
33
|
+
# User::Admin # => 'ADMIN'
|
34
|
+
# User::Manager # => 'MANAGER'
|
35
|
+
#
|
36
|
+
# User.employees # => [<#User role='EMPLOYEE'>, <#User role='EMPLOYEE'>]
|
37
|
+
# User.admin # => [<#User role='ADMIN'>, <#User role='ADMIN'>]
|
38
|
+
# User.manager # => [<#User role='MANAGER'>, <#User role='MANAGER'>]
|
39
|
+
#
|
40
|
+
# User.role_with(<KEYS>)
|
41
|
+
# User.role_with([:admin, :manager]) # => [<#User role='MANAGER'>, <#User role='ADMIN'>]
|
42
|
+
#
|
43
|
+
# User.role_keys # => [:employee, :admin, :manager]
|
44
|
+
# User.role_values # => ['EMPLOYEE', 'ADMIN', 'MANAGER']
|
45
|
+
#
|
46
|
+
# User.enum_value_for(role: <KEY>)
|
47
|
+
# User.enum_value_for(role: :employee) # => 'EMPLOYEE'
|
48
|
+
#
|
49
|
+
# User.role_value_for(<key>)
|
50
|
+
# User.role_value_for(:employee) # => 'EMPLOYEE'
|
51
|
+
#
|
52
|
+
def string_enum(validation: true, prefix: false, **enum_hash)
|
53
|
+
# enum_name = :role
|
54
|
+
enum_name = enum_hash.keys.first
|
55
|
+
|
56
|
+
# enum_keys = [:employee, :admin, :manager]
|
57
|
+
enum_keys = enum_hash[enum_name].freeze
|
58
|
+
|
59
|
+
# enum_keys_values = { employee: 'EMPLOYEE', admin: 'ADMIN', manager: 'MANAGER' }
|
60
|
+
enum_keys_values = enum_keys.index_with(&key_to_value)
|
61
|
+
|
62
|
+
# enum_values = ['EMPLOYEE', 'ADMIN', 'MANAGER']
|
63
|
+
enum_values = enum_keys_values.values
|
64
|
+
|
65
|
+
define_enum_methods(enum_name, enum_keys, enum_values, enum_keys_values, prefix)
|
66
|
+
|
67
|
+
# HACK: we want validation to be overridable while implementing framework
|
68
|
+
# To do that, each time we are overriding string enum, we must
|
69
|
+
# * Remove validations callback already set by ancestor's definition of string enum
|
70
|
+
# * Remove the validations from the list of classes validators
|
71
|
+
#
|
72
|
+
# find previously defined inclusion validation callback:
|
73
|
+
previous_validation_callback =
|
74
|
+
send(:get_callbacks, :validate)
|
75
|
+
.send(:chain)
|
76
|
+
.filter do |c|
|
77
|
+
c.filter.is_a?(ActiveModel::Validations::InclusionValidator) && c.filter.attributes.include?(enum_name)
|
78
|
+
end.first
|
79
|
+
|
80
|
+
# if such callback exists
|
81
|
+
if previous_validation_callback.present?
|
82
|
+
# get rid of it
|
83
|
+
send(:get_callbacks, :validate).send(:chain).delete(previous_validation_callback)
|
84
|
+
# remove the validation from classes validators
|
85
|
+
_validators[enum_name].delete_if { |v| v.instance_of?(ActiveModel::Validations::InclusionValidator) }
|
86
|
+
end
|
87
|
+
|
88
|
+
# implement validation based on current enum
|
89
|
+
# if validation is set to false, we've cleared inclusion validations on current enum
|
90
|
+
#
|
91
|
+
# validates(:role, inclusion: { in: ['EMPLOYEE', 'ADMIN', 'MANAGER'] }, allow_nil: true)
|
92
|
+
validates(enum_name, inclusion: {in: enum_values}, allow_nil: true) if validation
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def key_to_value
|
98
|
+
->(key) { key.to_s.upcase }
|
99
|
+
end
|
100
|
+
|
101
|
+
def define_enum_methods(enum_name, enum_keys, enum_values, enum_keys_values, prefix)
|
102
|
+
# for each keys define named methodes
|
103
|
+
enum_keys_values.each { |enum_key, enum_value| define_named_methodes(enum_name, enum_key, enum_value, prefix) }
|
104
|
+
|
105
|
+
# class.role_with(<KEYS>)
|
106
|
+
#
|
107
|
+
# def self.role_with([:admin, :manager])
|
108
|
+
# where(role: ['ADMIN', 'MANAGER'])
|
109
|
+
# end
|
110
|
+
define_singleton_method("#{enum_name}_with") do |*keys|
|
111
|
+
where(enum_name => Array(keys).flatten.map(&key_to_value))
|
112
|
+
end
|
113
|
+
|
114
|
+
# class.role_keys
|
115
|
+
#
|
116
|
+
# def self.role_keys
|
117
|
+
# [:employee, :admin, :manager]
|
118
|
+
# end
|
119
|
+
define_singleton_method("#{enum_name}_keys") { enum_keys }
|
120
|
+
|
121
|
+
# instance.role_keys
|
122
|
+
delegate("#{enum_name}_keys".to_sym, to: :class)
|
123
|
+
|
124
|
+
# class.role_values
|
125
|
+
#
|
126
|
+
# def self.role_values
|
127
|
+
# ['EMPLOYEE', 'ADMIN', 'MANAGER']
|
128
|
+
# end
|
129
|
+
define_singleton_method("#{enum_name}_values") { enum_values }
|
130
|
+
|
131
|
+
# instance.role_values
|
132
|
+
delegate("#{enum_name}_values".to_sym, to: :class)
|
133
|
+
|
134
|
+
define_enum_value_methods(enum_name, enum_keys, enum_keys_values)
|
135
|
+
end
|
136
|
+
|
137
|
+
def define_enum_value_methods(enum_name, enum_keys, enum_keys_values)
|
138
|
+
# class.enum_value_for(<enum_name>: <key>)
|
139
|
+
#
|
140
|
+
# def self.enum_value_for(role: :employee)
|
141
|
+
# 'EMPLOYEE'
|
142
|
+
# end
|
143
|
+
define_singleton_method(:enum_value_for) do |**args|
|
144
|
+
public_send("#{args.keys.first}_enum_value_for", args.values.first)
|
145
|
+
end
|
146
|
+
|
147
|
+
# class.<enum_name>_enum_value_for(<key>)
|
148
|
+
#
|
149
|
+
# def self.role_enum_value_for(:employee)
|
150
|
+
# 'EMPLOYEE'
|
151
|
+
# end
|
152
|
+
define_singleton_method("#{enum_name}_enum_value_for") do |enum_key|
|
153
|
+
enum_key = enum_key.to_sym
|
154
|
+
raise(ArgumentError, "unknown enum_key: #{enum_key}") unless enum_keys.include?(enum_key)
|
155
|
+
|
156
|
+
enum_keys_values[enum_key]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def define_named_methodes(enum_name, enum_key, enum_value, prefix)
|
161
|
+
# instance.<key>?
|
162
|
+
#
|
163
|
+
# def employee?
|
164
|
+
# role == 'EMPLOYEE'
|
165
|
+
# end
|
166
|
+
define_method("#{enum_key}?") { public_send(enum_name) == enum_value }
|
167
|
+
|
168
|
+
# instance.<key>!
|
169
|
+
#
|
170
|
+
# def employee!
|
171
|
+
# self.role = 'EMPLOYEE'
|
172
|
+
# end
|
173
|
+
define_method("#{enum_key}!") { public_send("#{enum_name}=", enum_value) }
|
174
|
+
|
175
|
+
# class::<Key>
|
176
|
+
# the class name follow by key as camelcase
|
177
|
+
#
|
178
|
+
# class::Employee
|
179
|
+
# => 'EMPLOYEE'
|
180
|
+
define_constant(enum_key, prefix ? enum_name : false)
|
181
|
+
|
182
|
+
# def self.employees
|
183
|
+
# where(role: 'EMPLOYEE')
|
184
|
+
# end
|
185
|
+
define_singleton_method(enum_key.to_s.pluralize) { where(enum_name => enum_value) }
|
186
|
+
end
|
187
|
+
|
188
|
+
def define_constant(enum_key, prefix)
|
189
|
+
prefix = prefix ? prefix.to_s + "_" : ""
|
190
|
+
constant_name = (prefix + enum_key.to_s).camelcase
|
191
|
+
return if const_defined?(constant_name, false)
|
192
|
+
|
193
|
+
const_set(
|
194
|
+
constant_name,
|
195
|
+
enum_key.to_s.underscore.upcase
|
196
|
+
)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<button class="navbar-toggler" id="navbarSideCollapse" onclick="this.classList.toggle('opened');this.setAttribute('aria-expanded', this.classList.contains('opened'))" aria-label="Main Menu">
|
2
|
+
<svg width="30" height="30" viewBox="0 0 100 100">
|
3
|
+
<path class="line line1" d="M 20,29.000046 H 80.000231 C 80.000231,29.000046 94.498839,28.817352 94.532987,66.711331 94.543142,77.980673 90.966081,81.670246 85.259173,81.668997 79.552261,81.667751 75.000211,74.999942 75.000211,74.999942 L 25.000021,25.000058" />
|
4
|
+
<path class="line line2" d="M 20,50 H 80" />
|
5
|
+
<path class="line line3" d="M 20,70.999954 H 80.000231 C 80.000231,70.999954 94.498839,71.182648 94.532987,33.288669 94.543142,22.019327 90.966081,18.329754 85.259173,18.331003 79.552261,18.332249 75.000211,25.000058 75.000211,25.000058 L 25.000021,74.999942" />
|
6
|
+
</svg>
|
7
|
+
</button>
|
File without changes
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="container-fluid px-0 header bg-secondary bg-opacity-25">
|
2
|
+
<nav class="navbar navbar-expand-lg px-3 py-0 shadow-sm">
|
3
|
+
<%= render "layouts/header/hamburger" %>
|
4
|
+
<%= render "layouts/header/logo" %>
|
5
|
+
<div class="navbar-collapse offcanvas-collapse on_top_of_iframe">
|
6
|
+
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
7
|
+
<%= root_path(t("header.home")) %>
|
8
|
+
</ul>
|
9
|
+
<%= link_to fa_icon("globe", text: current_language), "#languageModal", class: "nav-item nav-link link-dark", data: { bs_toggle: "modal", bs_target: "#languageModal"} %>
|
10
|
+
</div>
|
11
|
+
</nav>
|
12
|
+
</div>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%= stylesheet_link_tag "open_fresk/application", media: "all", "data-turbo-track": "reload" %>
|
2
|
+
<%= csrf_meta_tags %>
|
3
|
+
|
4
|
+
<%= favicon_link_tag "open_fresk/favicon.png", type: "image/png" %>
|
5
|
+
<%= favicon_link_tag "open_fresk/favicon.png", rel: "apple-touch-icon", type: "image/png" %>
|
6
|
+
|
7
|
+
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/cupertino/jquery-ui.min.css">
|
8
|
+
<link rel="manifest" href="<%= asset_path 'manifest.json' %>">
|
9
|
+
|
10
|
+
<script async src="https://ga.jspm.io/npm:es-module-shims@1.8.2/dist/es-module-shims.js" data-turbo-track="reload"></script>
|
11
|
+
|
12
|
+
|
13
|
+
<%= javascript_include_tag "open_fresk/application",
|
14
|
+
"data-turbo-track": "reload",
|
15
|
+
defer: true %>
|
16
|
+
|
17
|
+
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
|
18
|
+
<script src="https://code.jquery.com/ui/1.11.2/jquery-ui.min.js"></script>
|
19
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,400;0,700;1,100;1,400;1,700&display=swap" rel="stylesheet">
|
20
|
+
|
21
|
+
<%#— host-only extras hook —%>
|
22
|
+
<% if lookup_context.template_exists?("layouts/open_fresk/include_extras", [], true) %>
|
23
|
+
<%= render partial: "layouts/open_fresk/include_extras" %>
|
24
|
+
<% end %>
|