iron-cms 0.7.1 → 0.8.0
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 +4 -4
- data/app/assets/builds/iron.css +59 -0
- data/app/controllers/iron/passwords_controller.rb +8 -1
- data/app/controllers/iron/qr_codes_controller.rb +15 -0
- data/app/controllers/iron/sessions/transfers_controller.rb +21 -0
- data/app/controllers/iron/users_controller.rb +36 -8
- data/app/helpers/iron/application_helper.rb +5 -1
- data/app/helpers/iron/transfers_helper.rb +27 -0
- data/app/javascript/iron/controllers/copy_to_clipboard_controller.js +29 -0
- data/app/javascript/iron/controllers/web_share_controller.js +17 -0
- data/app/mailers/iron/passwords_mailer.rb +8 -0
- data/app/models/iron/email_configuration.rb +21 -0
- data/app/models/iron/qr_code_link.rb +28 -0
- data/app/models/iron/user/transferable.rb +15 -0
- data/app/models/iron/user.rb +1 -0
- data/app/views/iron/sessions/new.html.erb +5 -3
- data/app/views/iron/sessions/transfers/show.html.erb +16 -0
- data/app/views/iron/users/_invite.html.erb +56 -0
- data/app/views/iron/users/_transfer.html.erb +65 -0
- data/app/views/iron/users/_user.html.erb +7 -3
- data/app/views/iron/users/edit.html.erb +44 -7
- data/app/views/iron/users/index.html.erb +1 -9
- data/app/views/iron/users/new.html.erb +20 -12
- data/app/views/iron/users/show.html.erb +35 -14
- data/app/views/layouts/iron/_user_menu.html.erb +2 -2
- data/config/routes.rb +7 -2
- data/lib/iron/engine.rb +1 -0
- data/lib/iron/version.rb +1 -1
- metadata +27 -3
- data/app/mailers/passwords_mailer.rb +0 -6
- data/app/views/iron/users/_form.html.erb +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0394a59fdfcd9e2552d9aea3fe48e8b95f7d01813841b0c91a0ba9fb2cc08220'
|
|
4
|
+
data.tar.gz: 6b1125a24a88c762fe24b73c6d50b0a0a35f76bc802d89f073c55fb58d4d063d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dd37b2e6e68ccbb9993781cce2a0ccfbdf42ecd5247f36f010ff0ee1b97aed3228bc5cb4ac7961614617df8214985a950a8a67c86f904c83d341ce2a270449f0
|
|
7
|
+
data.tar.gz: cb47c4a18d861e37001015aeec7eff0f2d90ca7ba8fd7ca7daeb85e03387fbb39ea84e3104e5a4e86e99c1986f3ea6656398f63e4e516582f80b9260655b1dc0
|
data/app/assets/builds/iron.css
CHANGED
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
--container-2xs: 18rem;
|
|
50
50
|
--container-xs: 20rem;
|
|
51
51
|
--container-sm: 24rem;
|
|
52
|
+
--container-md: 28rem;
|
|
52
53
|
--container-2xl: 42rem;
|
|
53
54
|
--container-4xl: 56rem;
|
|
54
55
|
--text-xs: 0.75rem;
|
|
@@ -1839,6 +1840,9 @@
|
|
|
1839
1840
|
.table {
|
|
1840
1841
|
display: table;
|
|
1841
1842
|
}
|
|
1843
|
+
.aspect-square {
|
|
1844
|
+
aspect-ratio: 1 / 1;
|
|
1845
|
+
}
|
|
1842
1846
|
.size-4 {
|
|
1843
1847
|
width: calc(var(--spacing) * 4);
|
|
1844
1848
|
height: calc(var(--spacing) * 4);
|
|
@@ -1855,6 +1859,10 @@
|
|
|
1855
1859
|
width: calc(var(--spacing) * 8);
|
|
1856
1860
|
height: calc(var(--spacing) * 8);
|
|
1857
1861
|
}
|
|
1862
|
+
.size-auto {
|
|
1863
|
+
width: auto;
|
|
1864
|
+
height: auto;
|
|
1865
|
+
}
|
|
1858
1866
|
.size-full {
|
|
1859
1867
|
width: 100%;
|
|
1860
1868
|
height: 100%;
|
|
@@ -1886,6 +1894,9 @@
|
|
|
1886
1894
|
.max-h-60 {
|
|
1887
1895
|
max-height: calc(var(--spacing) * 60);
|
|
1888
1896
|
}
|
|
1897
|
+
.max-h-none {
|
|
1898
|
+
max-height: none;
|
|
1899
|
+
}
|
|
1889
1900
|
.min-h-56 {
|
|
1890
1901
|
min-height: calc(var(--spacing) * 56);
|
|
1891
1902
|
}
|
|
@@ -1940,6 +1951,9 @@
|
|
|
1940
1951
|
.max-w-96 {
|
|
1941
1952
|
max-width: calc(var(--spacing) * 96);
|
|
1942
1953
|
}
|
|
1954
|
+
.max-w-md {
|
|
1955
|
+
max-width: var(--container-md);
|
|
1956
|
+
}
|
|
1943
1957
|
.max-w-none {
|
|
1944
1958
|
max-width: none;
|
|
1945
1959
|
}
|
|
@@ -2063,6 +2077,13 @@
|
|
|
2063
2077
|
margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)));
|
|
2064
2078
|
}
|
|
2065
2079
|
}
|
|
2080
|
+
.space-y-2 {
|
|
2081
|
+
:where(& > :not(:last-child)) {
|
|
2082
|
+
--tw-space-y-reverse: 0;
|
|
2083
|
+
margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));
|
|
2084
|
+
margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2066
2087
|
.space-y-4 {
|
|
2067
2088
|
:where(& > :not(:last-child)) {
|
|
2068
2089
|
--tw-space-y-reverse: 0;
|
|
@@ -2277,6 +2298,12 @@
|
|
|
2277
2298
|
}
|
|
2278
2299
|
}
|
|
2279
2300
|
}
|
|
2301
|
+
.bg-black\/50 {
|
|
2302
|
+
background-color: color-mix(in srgb, #000 50%, transparent);
|
|
2303
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
2304
|
+
background-color: color-mix(in oklab, var(--color-black) 50%, transparent);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2280
2307
|
.bg-gray-100 {
|
|
2281
2308
|
background-color: var(--color-gray-100);
|
|
2282
2309
|
}
|
|
@@ -2328,6 +2355,9 @@
|
|
|
2328
2355
|
background-color: color-mix(in oklab, var(--color-stone-900) 80%, transparent);
|
|
2329
2356
|
}
|
|
2330
2357
|
}
|
|
2358
|
+
.bg-transparent {
|
|
2359
|
+
background-color: transparent;
|
|
2360
|
+
}
|
|
2331
2361
|
.bg-white {
|
|
2332
2362
|
background-color: var(--color-white);
|
|
2333
2363
|
}
|
|
@@ -2902,6 +2932,16 @@
|
|
|
2902
2932
|
opacity: 0%;
|
|
2903
2933
|
}
|
|
2904
2934
|
}
|
|
2935
|
+
.group-\[\.success\]\:hidden {
|
|
2936
|
+
&:is(:where(.group):is(.success) *) {
|
|
2937
|
+
display: none;
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
.group-\[\.success\]\:inline {
|
|
2941
|
+
&:is(:where(.group):is(.success) *) {
|
|
2942
|
+
display: inline;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2905
2945
|
.peer-has-\[\:checked\]\:block {
|
|
2906
2946
|
&:is(:where(.peer):has(*:is(:checked)) ~ *) {
|
|
2907
2947
|
display: block;
|
|
@@ -2981,6 +3021,13 @@
|
|
|
2981
3021
|
}
|
|
2982
3022
|
}
|
|
2983
3023
|
}
|
|
3024
|
+
.hover\:opacity-75 {
|
|
3025
|
+
&:hover {
|
|
3026
|
+
@media (hover: hover) {
|
|
3027
|
+
opacity: 75%;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
2984
3031
|
.focus\:bg-sky-100 {
|
|
2985
3032
|
&:focus {
|
|
2986
3033
|
background-color: var(--color-sky-100);
|
|
@@ -3100,6 +3147,12 @@
|
|
|
3100
3147
|
transition-duration: 100ms;
|
|
3101
3148
|
}
|
|
3102
3149
|
}
|
|
3150
|
+
.data-enter\:duration-300 {
|
|
3151
|
+
&[data-enter] {
|
|
3152
|
+
--tw-duration: 300ms;
|
|
3153
|
+
transition-duration: 300ms;
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3103
3156
|
.data-enter\:ease-out {
|
|
3104
3157
|
&[data-enter] {
|
|
3105
3158
|
--tw-ease: var(--ease-out);
|
|
@@ -3130,6 +3183,12 @@
|
|
|
3130
3183
|
transition-duration: 100ms;
|
|
3131
3184
|
}
|
|
3132
3185
|
}
|
|
3186
|
+
.data-leave\:duration-200 {
|
|
3187
|
+
&[data-leave] {
|
|
3188
|
+
--tw-duration: 200ms;
|
|
3189
|
+
transition-duration: 200ms;
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3133
3192
|
.data-leave\:ease-in {
|
|
3134
3193
|
&[data-leave] {
|
|
3135
3194
|
--tw-ease: var(--ease-in);
|
|
@@ -2,6 +2,7 @@ module Iron
|
|
|
2
2
|
class PasswordsController < ApplicationController
|
|
3
3
|
layout "iron/authentication"
|
|
4
4
|
allow_unauthenticated_access
|
|
5
|
+
before_action :require_email_configuration, only: %i[ new create ]
|
|
5
6
|
before_action :set_user_by_token, only: %i[ edit update ]
|
|
6
7
|
|
|
7
8
|
def new
|
|
@@ -9,7 +10,7 @@ module Iron
|
|
|
9
10
|
|
|
10
11
|
def create
|
|
11
12
|
if user = User.find_by(email_address: params[:email_address])
|
|
12
|
-
PasswordsMailer.reset(user).deliver_later
|
|
13
|
+
Iron::PasswordsMailer.reset(user).deliver_later
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
redirect_to new_session_url, notice: "Password reset instructions sent (if user with that email address exists)."
|
|
@@ -27,6 +28,12 @@ module Iron
|
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
private
|
|
31
|
+
def require_email_configuration
|
|
32
|
+
unless EmailConfiguration.available?
|
|
33
|
+
redirect_to sign_in_url, alert: "Email is not configured. Please contact an administrator for a transfer link."
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
30
37
|
def set_user_by_token
|
|
31
38
|
@user = User.find_by_password_reset_token!(params[:token])
|
|
32
39
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Iron
|
|
2
|
+
class QrCodesController < ApplicationController
|
|
3
|
+
allow_unauthenticated_access
|
|
4
|
+
|
|
5
|
+
def show
|
|
6
|
+
qr_code_link = QrCodeLink.from_signed(params[:id])
|
|
7
|
+
svg = RQRCode::QRCode.new(qr_code_link.url).as_svg(viewbox: true, fill: :white, color: :black)
|
|
8
|
+
|
|
9
|
+
expires_in 1.year, public: true
|
|
10
|
+
render plain: svg, content_type: "image/svg+xml"
|
|
11
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
|
12
|
+
head :bad_request
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Iron
|
|
2
|
+
module Sessions
|
|
3
|
+
class TransfersController < ApplicationController
|
|
4
|
+
layout "iron/authentication"
|
|
5
|
+
allow_unauthenticated_access
|
|
6
|
+
rate_limit to: 10, within: 3.minutes, only: :update, with: -> { redirect_to sign_in_url, alert: "Try again later." }
|
|
7
|
+
|
|
8
|
+
def show
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def update
|
|
12
|
+
if user = User.find_by_transfer_id(params[:id])
|
|
13
|
+
start_new_session_for user
|
|
14
|
+
redirect_to after_authentication_url
|
|
15
|
+
else
|
|
16
|
+
redirect_to sign_in_url, alert: "Transfer link is invalid or has expired."
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -3,9 +3,10 @@ module Iron
|
|
|
3
3
|
layout "iron/authentication", only: %i[ new create ]
|
|
4
4
|
require_unauthenticated_access only: %i[ new create ]
|
|
5
5
|
|
|
6
|
-
before_action :set_user, only: %i[ show update destroy ]
|
|
6
|
+
before_action :set_user, only: %i[ show edit update destroy ]
|
|
7
7
|
before_action :verify_join_code, only: %i[ new create ]
|
|
8
|
-
before_action :ensure_can_administer,
|
|
8
|
+
before_action :ensure_can_administer, only: %i[ index destroy ]
|
|
9
|
+
before_action :ensure_current_user, only: %i[ edit ]
|
|
9
10
|
|
|
10
11
|
def index
|
|
11
12
|
@users = User.all
|
|
@@ -18,7 +19,10 @@ module Iron
|
|
|
18
19
|
def show
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
def edit
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create
|
|
22
26
|
@user = User.new(join_params)
|
|
23
27
|
if @user.save
|
|
24
28
|
start_new_session_for @user
|
|
@@ -31,10 +35,10 @@ module Iron
|
|
|
31
35
|
end
|
|
32
36
|
|
|
33
37
|
def update
|
|
34
|
-
if @user.
|
|
35
|
-
|
|
38
|
+
if @user.current?
|
|
39
|
+
update_own_profile
|
|
36
40
|
else
|
|
37
|
-
|
|
41
|
+
update_user_role
|
|
38
42
|
end
|
|
39
43
|
end
|
|
40
44
|
|
|
@@ -55,12 +59,36 @@ module Iron
|
|
|
55
59
|
params.expect(user: [ :email_address, :password, :password_confirmation ])
|
|
56
60
|
end
|
|
57
61
|
|
|
58
|
-
def
|
|
59
|
-
params.
|
|
62
|
+
def profile_params
|
|
63
|
+
params.require(:user).permit(:email_address, :password, :password_confirmation)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def role_params
|
|
67
|
+
params.expect(user: [ :role ])
|
|
60
68
|
end
|
|
61
69
|
|
|
62
70
|
def verify_join_code
|
|
63
71
|
head :not_found if Current.account.join_code != params[:join_code]
|
|
64
72
|
end
|
|
73
|
+
|
|
74
|
+
def ensure_current_user
|
|
75
|
+
redirect_to @user, alert: "You can only edit your own profile." unless @user.current?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def update_own_profile
|
|
79
|
+
if @user.update(profile_params)
|
|
80
|
+
redirect_to @user, notice: "Profile updated."
|
|
81
|
+
else
|
|
82
|
+
render :edit, status: :unprocessable_entity
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def update_user_role
|
|
87
|
+
if @user.update(role_params)
|
|
88
|
+
redirect_back fallback_location: users_path, notice: "User was successfully updated.", status: :see_other
|
|
89
|
+
else
|
|
90
|
+
redirect_back fallback_location: users_path, alert: @user.errors.full_messages.to_sentence, status: :see_other
|
|
91
|
+
end
|
|
92
|
+
end
|
|
65
93
|
end
|
|
66
94
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require "tailwind_merge"
|
|
2
2
|
module Iron
|
|
3
3
|
module ApplicationHelper
|
|
4
|
-
include IconsHelper, AvatarHelper, UiHelper, EntriesHelper, ContentTypesHelper
|
|
4
|
+
include IconsHelper, AvatarHelper, UiHelper, EntriesHelper, ContentTypesHelper, TransfersHelper
|
|
5
5
|
|
|
6
6
|
TAILWIND_MERGER = TailwindMerge::Merger.new.freeze
|
|
7
7
|
|
|
@@ -12,5 +12,9 @@ module Iron
|
|
|
12
12
|
def unique_id
|
|
13
13
|
rand(10000000..100000000)
|
|
14
14
|
end
|
|
15
|
+
|
|
16
|
+
def email_configured?
|
|
17
|
+
EmailConfiguration.available?
|
|
18
|
+
end
|
|
15
19
|
end
|
|
16
20
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Iron
|
|
2
|
+
module TransfersHelper
|
|
3
|
+
def button_to_copy_to_clipboard(url, &block)
|
|
4
|
+
tag.button class: "button-secondary group", data: {
|
|
5
|
+
controller: "copy-to-clipboard",
|
|
6
|
+
action: "copy-to-clipboard#copy",
|
|
7
|
+
copy_to_clipboard_content_value: url,
|
|
8
|
+
copy_to_clipboard_success_class: "success"
|
|
9
|
+
}, &block
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def web_share_button(url, title, text, &block)
|
|
13
|
+
tag.button class: "button-secondary", hidden: true, data: {
|
|
14
|
+
controller: "web-share",
|
|
15
|
+
action: "web-share#share",
|
|
16
|
+
web_share_url_value: url,
|
|
17
|
+
web_share_text_value: text,
|
|
18
|
+
web_share_title_value: title
|
|
19
|
+
}, &block
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def qr_code_image(url)
|
|
23
|
+
qr_code_link = QrCodeLink.new(url)
|
|
24
|
+
image_tag qr_code_path(qr_code_link.signed), class: "aspect-square", alt: "QR Code"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static values = {
|
|
5
|
+
content: String,
|
|
6
|
+
successDuration: { type: Number, default: 1500 }
|
|
7
|
+
}
|
|
8
|
+
static classes = ["success"]
|
|
9
|
+
|
|
10
|
+
async copy(event) {
|
|
11
|
+
event.preventDefault()
|
|
12
|
+
this.reset()
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
await navigator.clipboard.writeText(this.contentValue)
|
|
16
|
+
this.element.classList.add(this.successClass)
|
|
17
|
+
setTimeout(() => this.reset(), this.successDurationValue)
|
|
18
|
+
} catch { }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
reset() {
|
|
22
|
+
this.element.classList.remove(this.successClass)
|
|
23
|
+
this.#forceReflow()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#forceReflow() {
|
|
27
|
+
this.element.offsetWidth
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static values = { title: String, text: String, url: String }
|
|
5
|
+
|
|
6
|
+
connect() {
|
|
7
|
+
this.element.hidden = !navigator.canShare
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async share() {
|
|
11
|
+
await navigator.share({
|
|
12
|
+
title: this.titleValue,
|
|
13
|
+
text: this.textValue,
|
|
14
|
+
url: this.urlValue
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Iron
|
|
2
|
+
class EmailConfiguration
|
|
3
|
+
def self.available?
|
|
4
|
+
delivery_method = ActionMailer::Base.delivery_method
|
|
5
|
+
|
|
6
|
+
case delivery_method
|
|
7
|
+
when :smtp
|
|
8
|
+
ActionMailer::Base.smtp_settings[:address].present?
|
|
9
|
+
when :sendmail, :file
|
|
10
|
+
true
|
|
11
|
+
when :test
|
|
12
|
+
Rails.env.test?
|
|
13
|
+
else
|
|
14
|
+
# Allow other delivery methods (postmark, sendgrid, etc.)
|
|
15
|
+
true
|
|
16
|
+
end
|
|
17
|
+
rescue
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Iron
|
|
2
|
+
class QrCodeLink
|
|
3
|
+
attr_reader :url
|
|
4
|
+
|
|
5
|
+
def initialize(url)
|
|
6
|
+
@url = url
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def signed
|
|
10
|
+
self.class.verifier.generate(@url, purpose: :qr_code)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.from_signed(signed)
|
|
14
|
+
new verifier.verify(signed, purpose: :qr_code)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
class << self
|
|
19
|
+
def verifier
|
|
20
|
+
ActiveSupport::MessageVerifier.new(secret, url_safe: true)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def secret
|
|
24
|
+
Rails.application.key_generator.generate_key("iron_qr_codes")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Iron::User::Transferable
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
TRANSFER_LINK_EXPIRY_DURATION = 4.hours
|
|
5
|
+
|
|
6
|
+
class_methods do
|
|
7
|
+
def find_by_transfer_id(id)
|
|
8
|
+
find_signed(id, purpose: :transfer)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def transfer_id
|
|
13
|
+
signed_id(purpose: :transfer, expires_in: TRANSFER_LINK_EXPIRY_DURATION)
|
|
14
|
+
end
|
|
15
|
+
end
|
data/app/models/iron/user.rb
CHANGED
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
<div>
|
|
19
19
|
<div class="flex items-center justify-between">
|
|
20
20
|
<%= form.label :password, "Password", class: "block text-sm/6 font-medium text-stone-900 dark:text-stone-100" %>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
<% if email_configured? %>
|
|
22
|
+
<div class="text-sm">
|
|
23
|
+
<%= link_to "Forgot password?", new_password_path, class: "font-semibold text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300" %>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
|
24
26
|
</div>
|
|
25
27
|
<div class="mt-2">
|
|
26
28
|
<%= form.password_field :password,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
|
2
|
+
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-stone-900 dark:text-white">Confirm sign in</h2>
|
|
3
|
+
<p class="mt-2 text-center text-sm/6 text-stone-500 dark:text-stone-400">You're about to sign in using a transfer link</p>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
|
7
|
+
<%= form_with url: session_transfer_path(params[:id]), method: :put, class: "space-y-6" do |form| %>
|
|
8
|
+
<div>
|
|
9
|
+
<%= form.submit "Sign in", class: "button-primary w-full" %>
|
|
10
|
+
</div>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<p class="mt-10 text-center text-sm/6 text-stone-500 dark:text-stone-400">
|
|
14
|
+
<%= link_to "Back to sign in", sign_in_path, class: "font-semibold text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300" %>
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<% url = join_url(Iron::Current.account.join_code) %>
|
|
2
|
+
|
|
3
|
+
<div class="max-w-md">
|
|
4
|
+
<div class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm p-6 space-y-4">
|
|
5
|
+
<div class="space-y-2">
|
|
6
|
+
<h3 class="text-sm font-medium text-stone-900 dark:text-white">Invite Users</h3>
|
|
7
|
+
<p class="text-sm text-stone-500 dark:text-stone-400">Share this link to invite people to join</p>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div class="field">
|
|
11
|
+
<label for="join-url" class="sr-only">Invitation URL</label>
|
|
12
|
+
<input type="text" id="join-url" class="input" value="<%= url %>" readonly>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="flex items-center gap-2">
|
|
16
|
+
<div>
|
|
17
|
+
<button command="show-modal" commandfor="invite-qr-code-dialog" class="button-secondary">
|
|
18
|
+
<%= icon "qr-code", class: "size-4" %>
|
|
19
|
+
<span>Show QR code</span>
|
|
20
|
+
</button>
|
|
21
|
+
|
|
22
|
+
<el-dialog>
|
|
23
|
+
<dialog id="invite-qr-code-dialog" class="fixed inset-0 size-auto max-h-none max-w-none overflow-y-auto bg-transparent backdrop:bg-transparent">
|
|
24
|
+
<el-dialog-backdrop class="fixed inset-0 bg-black/50 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in"></el-dialog-backdrop>
|
|
25
|
+
|
|
26
|
+
<div tabindex="0" class="flex min-h-full items-center justify-center p-4 focus:outline-none">
|
|
27
|
+
<el-dialog-panel class="relative transform overflow-hidden rounded-lg bg-white p-6 shadow-xl transition-all data-closed:scale-95 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in dark:bg-stone-800">
|
|
28
|
+
<div class="flex flex-col items-center gap-4">
|
|
29
|
+
<div class="w-64">
|
|
30
|
+
<%= qr_code_image(url) %>
|
|
31
|
+
</div>
|
|
32
|
+
<button type="button" command="close" commandfor="invite-qr-code-dialog" class="button-secondary">
|
|
33
|
+
<%= icon "x", class: "size-4" %>
|
|
34
|
+
<span>Close</span>
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
37
|
+
</el-dialog-panel>
|
|
38
|
+
</div>
|
|
39
|
+
</dialog>
|
|
40
|
+
</el-dialog>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<%= button_to_copy_to_clipboard(url) do %>
|
|
44
|
+
<%= icon "copy", class: "size-4 group-[.success]:hidden" %>
|
|
45
|
+
<%= icon "check", class: "size-4 hidden group-[.success]:inline" %>
|
|
46
|
+
<span class="group-[.success]:hidden">Copy</span>
|
|
47
|
+
<span class="hidden group-[.success]:inline">Copied</span>
|
|
48
|
+
<% end %>
|
|
49
|
+
|
|
50
|
+
<%= web_share_button(url, "Join invitation", "Use this link to join as a new user.") do %>
|
|
51
|
+
<%= icon "share", class: "size-4" %>
|
|
52
|
+
<span>Share</span>
|
|
53
|
+
<% end %>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<%# locals: (user:) -%>
|
|
2
|
+
<% url = session_transfer_url(user.transfer_id) %>
|
|
3
|
+
|
|
4
|
+
<div class="space-y-4">
|
|
5
|
+
<div class="space-y-2">
|
|
6
|
+
<% if Iron::Current.user != user %>
|
|
7
|
+
<h3 class="text-sm font-medium text-stone-900 dark:text-white">Account Recovery Link</h3>
|
|
8
|
+
<p class="text-sm text-stone-500 dark:text-stone-400">Share this link to help them sign in on another device</p>
|
|
9
|
+
<% else %>
|
|
10
|
+
<h3 class="text-sm font-medium text-stone-900 dark:text-white">Transfer Session</h3>
|
|
11
|
+
<p class="text-sm text-stone-500 dark:text-stone-400">Use this link to automatically sign in on another device</p>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="field">
|
|
16
|
+
<label for="session_transfer_url" class="sr-only">Auto-login URL</label>
|
|
17
|
+
<input type="text" id="session_transfer_url" value="<%= url %>" readonly class="input">
|
|
18
|
+
<p class="text-xs text-stone-400 dark:text-stone-500 mt-2">
|
|
19
|
+
This link expires in 4 hours.
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
<div class="flex items-center gap-2">
|
|
25
|
+
<div>
|
|
26
|
+
<button command="show-modal" commandfor="qr-code-dialog" class="button-secondary">
|
|
27
|
+
<%= icon "qr-code", class: "size-4" %>
|
|
28
|
+
<span class="">Show QR code</span>
|
|
29
|
+
</button>
|
|
30
|
+
|
|
31
|
+
<el-dialog>
|
|
32
|
+
<dialog id="qr-code-dialog" class="fixed inset-0 size-auto max-h-none max-w-none overflow-y-auto bg-transparent backdrop:bg-transparent">
|
|
33
|
+
<el-dialog-backdrop class="fixed inset-0 bg-black/50 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in"></el-dialog-backdrop>
|
|
34
|
+
|
|
35
|
+
<div tabindex="0" class="flex min-h-full items-center justify-center p-4 focus:outline-none">
|
|
36
|
+
<el-dialog-panel class="relative transform overflow-hidden rounded-lg bg-white p-6 shadow-xl transition-all data-closed:scale-95 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in dark:bg-stone-800">
|
|
37
|
+
<div class="flex flex-col items-center gap-4">
|
|
38
|
+
<div class="w-64">
|
|
39
|
+
<%= qr_code_image(url) %>
|
|
40
|
+
</div>
|
|
41
|
+
<button type="button" command="close" commandfor="qr-code-dialog" class="button-secondary">
|
|
42
|
+
<%= icon "x", class: "size-4" %>
|
|
43
|
+
<span>Close</span>
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
</el-dialog-panel>
|
|
47
|
+
</div>
|
|
48
|
+
</dialog>
|
|
49
|
+
</el-dialog>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<%= button_to_copy_to_clipboard(url) do %>
|
|
53
|
+
<%= icon "copy", class: "size-4 group-[.success]:hidden" %>
|
|
54
|
+
<%= icon "check", class: "size-4 hidden group-[.success]:inline" %>
|
|
55
|
+
<span class="group-[.success]:hidden">Copy</span>
|
|
56
|
+
<span class="hidden group-[.success]:inline">Copied</span>
|
|
57
|
+
<% end %>
|
|
58
|
+
|
|
59
|
+
<%= web_share_button(url, "Your sign-in link", "This is your private sign-in URL. Use it to sign in on another device.") do %>
|
|
60
|
+
<%= icon "share", class: "size-4" %>
|
|
61
|
+
<span class="">Share link</span>
|
|
62
|
+
<% end %>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
</div>
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
<div class="block px-6 py-3">
|
|
3
3
|
<div class="flex items-center justify-between gap-4">
|
|
4
4
|
<div class="flex flex-col sm:flex-row sm:items-center sm:gap-8 min-w-0 flex-1">
|
|
5
|
-
|
|
5
|
+
<%= link_to user_path(user), class: "flex items-center gap-3 shrink-0 hover:opacity-75 transition-opacity" do %>
|
|
6
6
|
<h3 class="text-base font-semibold text-stone-900 dark:text-white truncate"><%= user.name %></h3>
|
|
7
7
|
<span class="text-sm text-stone-400"><%= user.email_address %></span>
|
|
8
|
-
|
|
8
|
+
<% end %>
|
|
9
9
|
</div>
|
|
10
|
-
<div>
|
|
10
|
+
<div class="flex items-center gap-2">
|
|
11
11
|
<% if user.current? %>
|
|
12
12
|
<%= badge user.role, class: ("badge-blue" if user.administrator?) %>
|
|
13
13
|
<% else %>
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
22
22
|
<% end %>
|
|
23
|
+
<%= button_to user_path(user), method: :delete, class: "button-destructive-icon", data: { turbo_confirm: "Are you sure you want to remove #{user.name}?" } do %>
|
|
24
|
+
<%= icon "trash-2", class: "size-4" %>
|
|
25
|
+
<span class="sr-only">Remove <%= user.name %></span>
|
|
26
|
+
<% end %>
|
|
23
27
|
<% end %>
|
|
24
28
|
</div>
|
|
25
29
|
</div>
|
|
@@ -1,12 +1,49 @@
|
|
|
1
|
-
<% content_for :title, "
|
|
1
|
+
<% content_for :title, "Edit Profile" %>
|
|
2
2
|
|
|
3
|
-
<
|
|
3
|
+
<div class="space-y-8">
|
|
4
|
+
<%= back_button_to "My Account", user_path(@user) %>
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
<div class="flex justify-between items-center">
|
|
7
|
+
<h1 class="page-title">Edit Profile</h1>
|
|
8
|
+
</div>
|
|
6
9
|
|
|
7
|
-
<
|
|
10
|
+
<div class="max-w-md">
|
|
11
|
+
<%= form_with(model: @user, class: "space-y-6") do |form| %>
|
|
12
|
+
<div class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm p-6 space-y-4">
|
|
13
|
+
<div class="field">
|
|
14
|
+
<%= form.label :email_address, "Email" %>
|
|
15
|
+
<div>
|
|
16
|
+
<%= form.email_field :email_address, autocomplete: "email" %>
|
|
17
|
+
<%= form.error_for :email_address %>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
8
21
|
|
|
9
|
-
<div>
|
|
10
|
-
|
|
11
|
-
|
|
22
|
+
<div class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm p-6 space-y-4">
|
|
23
|
+
<h2 class="text-sm font-medium text-stone-900 dark:text-white">Change Password</h2>
|
|
24
|
+
<p class="text-sm text-stone-500 dark:text-stone-400">Leave blank to keep your current password</p>
|
|
25
|
+
|
|
26
|
+
<div class="field">
|
|
27
|
+
<%= form.label :password, "New password" %>
|
|
28
|
+
<div>
|
|
29
|
+
<%= form.password_field :password, autocomplete: "new-password", maxlength: 72 %>
|
|
30
|
+
<%= form.error_for :password %>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="field">
|
|
35
|
+
<%= form.label :password_confirmation, "Confirm new password" %>
|
|
36
|
+
<div>
|
|
37
|
+
<%= form.password_field :password_confirmation, autocomplete: "new-password", maxlength: 72 %>
|
|
38
|
+
<%= form.error_for :password_confirmation %>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="flex gap-3">
|
|
44
|
+
<%= form.submit "Save changes", class: "button-primary" %>
|
|
45
|
+
<%= link_to "Cancel", user_path(@user), class: "button-secondary" %>
|
|
46
|
+
</div>
|
|
47
|
+
<% end %>
|
|
48
|
+
</div>
|
|
12
49
|
</div>
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
<% content_for :title, "Users" %>
|
|
2
2
|
|
|
3
|
-
<% url = join_url(Iron::Current.account.join_code) %>
|
|
4
|
-
|
|
5
3
|
<div class="space-y-8">
|
|
6
4
|
<div class="flex justify-between items-center">
|
|
7
5
|
<h1 class="page-title">Users</h1>
|
|
8
6
|
</div>
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
<h2>Invite users</h2>
|
|
12
|
-
<div class="field">
|
|
13
|
-
<label for="join-url">Share to invite people to join</label>
|
|
14
|
-
<input type="text" id="join-url" class="input" value="<%= url %>" readonly>
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
8
|
+
<%= render "iron/users/invite" %>
|
|
17
9
|
|
|
18
10
|
<div id="users" class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm divide-y divide-stone-200 dark:divide-stone-700/20 overflow-hidden">
|
|
19
11
|
<%= render @users %>
|
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
<% content_for :title, "Join #{Iron::Current.account.name}" %>
|
|
2
2
|
|
|
3
|
-
<div>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
</div>
|
|
3
|
+
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
|
4
|
+
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-stone-900 dark:text-white">Join <%= Iron::Current.account.name %></h2>
|
|
5
|
+
</div>
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
|
8
|
+
<%= form_with(model: @user, url: join_path(params[:join_code]), class: "space-y-6") do |form| %>
|
|
9
9
|
<div>
|
|
10
|
-
<%= form.label :email_address %>
|
|
11
|
-
|
|
10
|
+
<%= form.label :email_address, "Email address", class: "block text-sm/6 font-medium text-stone-900 dark:text-stone-100" %>
|
|
11
|
+
<div class="mt-2">
|
|
12
|
+
<%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "email" %>
|
|
13
|
+
</div>
|
|
12
14
|
<%= form.error_for :email_address %>
|
|
13
15
|
</div>
|
|
14
16
|
|
|
15
17
|
<div>
|
|
16
|
-
<%= form.label :password %>
|
|
17
|
-
|
|
18
|
+
<%= form.label :password, "Password", class: "block text-sm/6 font-medium text-stone-900 dark:text-stone-100" %>
|
|
19
|
+
<div class="mt-2">
|
|
20
|
+
<%= form.password_field :password, required: true, autocomplete: "new-password" %>
|
|
21
|
+
</div>
|
|
18
22
|
<%= form.error_for :password %>
|
|
19
23
|
</div>
|
|
20
24
|
|
|
21
25
|
<div>
|
|
22
|
-
<%= form.label :password_confirmation %>
|
|
23
|
-
|
|
26
|
+
<%= form.label :password_confirmation, "Password confirmation", class: "block text-sm/6 font-medium text-stone-900 dark:text-stone-100" %>
|
|
27
|
+
<div class="mt-2">
|
|
28
|
+
<%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
|
|
29
|
+
</div>
|
|
24
30
|
<%= form.error_for :password_confirmation %>
|
|
25
31
|
</div>
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
<div>
|
|
34
|
+
<%= form.submit "Join", class: "button-primary w-full" %>
|
|
35
|
+
</div>
|
|
28
36
|
<% end %>
|
|
29
37
|
</div>
|
|
@@ -1,18 +1,39 @@
|
|
|
1
|
-
<% content_for :title, "
|
|
1
|
+
<% content_for :title, @user.current? ? "My Account" : @user.name %>
|
|
2
2
|
|
|
3
|
-
<div
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end %>
|
|
14
|
-
</div>
|
|
3
|
+
<div class="space-y-8">
|
|
4
|
+
<% unless @user.current? %>
|
|
5
|
+
<%= back_button_to "Users", users_path %>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<div class="flex justify-between items-center">
|
|
9
|
+
<h1 class="page-title"><%= @user.current? ? "My Account" : @user.name %></h1>
|
|
10
|
+
<% if @user.current? %>
|
|
11
|
+
<%= link_to "Edit", edit_user_path(@user), class: "button-secondary" %>
|
|
12
|
+
<% end %>
|
|
15
13
|
</div>
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
<div class="max-w-md space-y-6">
|
|
16
|
+
<div class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm p-6">
|
|
17
|
+
<div class="space-y-4">
|
|
18
|
+
<div class="field">
|
|
19
|
+
<label class="label">Email</label>
|
|
20
|
+
<p class="text-stone-900 dark:text-white"><%= @user.email_address %></p>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="field">
|
|
23
|
+
<label class="label">Role</label>
|
|
24
|
+
<p class="text-stone-900 dark:text-white"><%= @user.role.titleize %></p>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm p-6">
|
|
30
|
+
<%= render "iron/users/transfer", user: @user %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<% if @user.current? %>
|
|
34
|
+
<div class="bg-white dark:bg-stone-800/50 rounded-lg shadow-sm p-6">
|
|
35
|
+
<%= button_to "Sign out", session_path, method: :delete, class: "button-outline w-full" %>
|
|
36
|
+
</div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
18
39
|
</div>
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
<el-menu anchor="<%= anchor %>" popover class="<%= anchor.include?('top') ? 'mx-2' : '' %> w-56 origin-bottom-right divide-y divide-stone-100 rounded-md bg-white shadow-lg outline-1 outline-black/5 transition transition-discrete [--anchor-gap:--spacing(2)] data-closed:scale-95 data-closed:transform data-closed:opacity-0 data-enter:duration-100 data-enter:ease-out data-leave:duration-75 data-leave:ease-in dark:divide-white/10 dark:bg-stone-800 dark:shadow-none dark:-outline-offset-1 dark:outline-white/10">
|
|
13
13
|
<div class="py-1">
|
|
14
|
-
|
|
14
|
+
<%= link_to user_path(Iron::Current.user), class: "group/item flex items-center px-4 py-2 text-sm text-stone-700 focus:bg-stone-100 focus:text-stone-900 focus:outline-hidden dark:text-stone-300 dark:focus:bg-white/5 dark:focus:text-white" do %>
|
|
15
15
|
<%= icon "circle-user", class: "mr-3 size-5 text-stone-400 group-focus/item:text-stone-500 dark:text-stone-500 dark:group-focus/item:text-white" %>
|
|
16
16
|
My account
|
|
17
|
-
|
|
17
|
+
<% end %>
|
|
18
18
|
</div>
|
|
19
19
|
<div class="py-1">
|
|
20
20
|
<%= button_to session_path, method: :delete, class: "group/item w-full flex items-center px-4 py-2 text-sm text-stone-700 focus:bg-stone-100 focus:text-stone-900 focus:outline-hidden dark:text-stone-300 dark:focus:bg-white/5 dark:focus:text-white" do %>
|
data/config/routes.rb
CHANGED
|
@@ -27,13 +27,18 @@ Iron::Engine.routes.draw do
|
|
|
27
27
|
resources :locales, except: %i[ show ]
|
|
28
28
|
|
|
29
29
|
resource :settings, only: %i[ show update ]
|
|
30
|
-
resources :users, only: %i[ index show update destroy ]
|
|
30
|
+
resources :users, only: %i[ index show edit update destroy ]
|
|
31
31
|
|
|
32
32
|
# Authentication
|
|
33
33
|
get "join/:join_code", to: "users#new", as: :join
|
|
34
34
|
post "join/:join_code", to: "users#create"
|
|
35
35
|
get "sign_in", to: "sessions#new"
|
|
36
36
|
post "sign_in", to: "sessions#create"
|
|
37
|
-
resource :session, only: %i[ destroy ]
|
|
37
|
+
resource :session, only: %i[ destroy ] do
|
|
38
|
+
scope module: "sessions" do
|
|
39
|
+
resources :transfers, only: %i[ show update ]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
38
42
|
resources :passwords, param: :token
|
|
43
|
+
resources :qr_codes, only: :show
|
|
39
44
|
end
|
data/lib/iron/engine.rb
CHANGED
data/lib/iron/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iron-cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Massimo De Marchi
|
|
@@ -191,6 +191,20 @@ dependencies:
|
|
|
191
191
|
- - "~>"
|
|
192
192
|
- !ruby/object:Gem::Version
|
|
193
193
|
version: '2.3'
|
|
194
|
+
- !ruby/object:Gem::Dependency
|
|
195
|
+
name: rqrcode
|
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
|
197
|
+
requirements:
|
|
198
|
+
- - "~>"
|
|
199
|
+
- !ruby/object:Gem::Version
|
|
200
|
+
version: '2.2'
|
|
201
|
+
type: :runtime
|
|
202
|
+
prerelease: false
|
|
203
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
204
|
+
requirements:
|
|
205
|
+
- - "~>"
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '2.2'
|
|
194
208
|
description: A Rails engine for managing and publishing content with a flexible schema.
|
|
195
209
|
email:
|
|
196
210
|
- massimo@inkofpixel.com
|
|
@@ -236,7 +250,9 @@ files:
|
|
|
236
250
|
- app/controllers/iron/icons_controller.rb
|
|
237
251
|
- app/controllers/iron/locales_controller.rb
|
|
238
252
|
- app/controllers/iron/passwords_controller.rb
|
|
253
|
+
- app/controllers/iron/qr_codes_controller.rb
|
|
239
254
|
- app/controllers/iron/references_controller.rb
|
|
255
|
+
- app/controllers/iron/sessions/transfers_controller.rb
|
|
240
256
|
- app/controllers/iron/sessions_controller.rb
|
|
241
257
|
- app/controllers/iron/settings_controller.rb
|
|
242
258
|
- app/controllers/iron/users_controller.rb
|
|
@@ -248,9 +264,11 @@ files:
|
|
|
248
264
|
- app/helpers/iron/form_builder.rb
|
|
249
265
|
- app/helpers/iron/icons_helper.rb
|
|
250
266
|
- app/helpers/iron/image_helper.rb
|
|
267
|
+
- app/helpers/iron/transfers_helper.rb
|
|
251
268
|
- app/helpers/iron/ui_helper.rb
|
|
252
269
|
- app/javascript/iron/application.js
|
|
253
270
|
- app/javascript/iron/controllers/application.js
|
|
271
|
+
- app/javascript/iron/controllers/copy_to_clipboard_controller.js
|
|
254
272
|
- app/javascript/iron/controllers/element_controller.js
|
|
255
273
|
- app/javascript/iron/controllers/file_upload_controller.js
|
|
256
274
|
- app/javascript/iron/controllers/form_controller.js
|
|
@@ -260,13 +278,14 @@ files:
|
|
|
260
278
|
- app/javascript/iron/controllers/local_preference_controller.js
|
|
261
279
|
- app/javascript/iron/controllers/sortable_list_controller.js
|
|
262
280
|
- app/javascript/iron/controllers/toggle_controller.js
|
|
281
|
+
- app/javascript/iron/controllers/web_share_controller.js
|
|
263
282
|
- app/javascript/iron/lib/lexorank.js
|
|
264
283
|
- app/jobs/iron/application_job.rb
|
|
265
284
|
- app/jobs/iron/export_job.rb
|
|
266
285
|
- app/jobs/iron/generate_entry_routes_job.rb
|
|
267
286
|
- app/jobs/iron/import_job.rb
|
|
268
287
|
- app/mailers/iron/application_mailer.rb
|
|
269
|
-
- app/mailers/passwords_mailer.rb
|
|
288
|
+
- app/mailers/iron/passwords_mailer.rb
|
|
270
289
|
- app/models/concerns/iron/broadcastable.rb
|
|
271
290
|
- app/models/concerns/iron/instance_scoped.rb
|
|
272
291
|
- app/models/concerns/iron/processable.rb
|
|
@@ -287,6 +306,7 @@ files:
|
|
|
287
306
|
- app/models/iron/content_types/collection.rb
|
|
288
307
|
- app/models/iron/content_types/single.rb
|
|
289
308
|
- app/models/iron/current.rb
|
|
309
|
+
- app/models/iron/email_configuration.rb
|
|
290
310
|
- app/models/iron/entry.rb
|
|
291
311
|
- app/models/iron/entry/deep_validation.rb
|
|
292
312
|
- app/models/iron/entry/exportable.rb
|
|
@@ -325,10 +345,12 @@ files:
|
|
|
325
345
|
- app/models/iron/first_run.rb
|
|
326
346
|
- app/models/iron/icon_catalog.rb
|
|
327
347
|
- app/models/iron/locale.rb
|
|
348
|
+
- app/models/iron/qr_code_link.rb
|
|
328
349
|
- app/models/iron/reference.rb
|
|
329
350
|
- app/models/iron/session.rb
|
|
330
351
|
- app/models/iron/user.rb
|
|
331
352
|
- app/models/iron/user/role.rb
|
|
353
|
+
- app/models/iron/user/transferable.rb
|
|
332
354
|
- app/views/active_storage/blobs/_blob.html.erb
|
|
333
355
|
- app/views/iron/account/exports/index.html.erb
|
|
334
356
|
- app/views/iron/account/exports/new.html.erb
|
|
@@ -400,10 +422,12 @@ files:
|
|
|
400
422
|
- app/views/iron/published_pages/show.html.erb
|
|
401
423
|
- app/views/iron/references/new.turbo_stream.erb
|
|
402
424
|
- app/views/iron/sessions/new.html.erb
|
|
425
|
+
- app/views/iron/sessions/transfers/show.html.erb
|
|
403
426
|
- app/views/iron/settings/show.html.erb
|
|
404
427
|
- app/views/iron/shared/_icon_picker.html.erb
|
|
405
428
|
- app/views/iron/shared/_select.html.erb
|
|
406
|
-
- app/views/iron/users/
|
|
429
|
+
- app/views/iron/users/_invite.html.erb
|
|
430
|
+
- app/views/iron/users/_transfer.html.erb
|
|
407
431
|
- app/views/iron/users/_user.html.erb
|
|
408
432
|
- app/views/iron/users/edit.html.erb
|
|
409
433
|
- app/views/iron/users/index.html.erb
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<%= form_with(model: user, class: "mt-4 max-w-96") do |form| %>
|
|
2
|
-
<div class="flex flex-col gap-3">
|
|
3
|
-
<div class="field">
|
|
4
|
-
<%= form.label :email_address, "Email" %>
|
|
5
|
-
<div>
|
|
6
|
-
<%= form.text_field :email_address %>
|
|
7
|
-
<%= form.error_for :email_address %>
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<div class="field">
|
|
12
|
-
<%= form.label :role, "User role" %>
|
|
13
|
-
<div>
|
|
14
|
-
<%= form.collection_select :role, Iron::User.roles.keys, :to_s, :titleize %>
|
|
15
|
-
<%= form.error_for :role %>
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
|
|
20
|
-
<%= form.submit class: "button-primary mt-4" %>
|
|
21
|
-
<% end %>
|