28 |
29 |
--------------------------------------------------------------------------------
/resources/stubs/Model.stub:
--------------------------------------------------------------------------------
1 | logFillable()->setDescriptionForEvent(fn(string $eventName) => auth()->user()?->name." {$eventName} ".$this->getTable());
24 | }
25 |
26 | public function getCreatedAtAttribute()
27 | {
28 | return Carbon::parse($this->attributes['created_at'])->isoFormat('D MMMM Y HH:mm');
29 | }
30 |
31 | public function getUpdatedAtAttribute()
32 | {
33 | return Carbon::parse($this->attributes['updated_at'])->isoFormat('D MMMM Y HH:mm');
34 | }
35 |
36 | /**
37 | * Get the user that owns the Setting
38 | *
39 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
40 | */
41 | public function user(): BelongsTo
42 | {
43 | return $this->belongsTo(User::class);
44 | }
45 | }
--------------------------------------------------------------------------------
/resources/js/bootstrap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * We'll load the axios HTTP library which allows us to easily issue requests
3 | * to our Laravel back-end. This library automatically handles sending the
4 | * CSRF token as a header based on the value of the "XSRF" token cookie.
5 | */
6 |
7 | import axios from 'axios';
8 | window.axios = axios;
9 |
10 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
11 |
12 | /**
13 | * Echo exposes an expressive API for subscribing to channels and listening
14 | * for events that are broadcast by Laravel. Echo and event broadcasting
15 | * allows your team to easily build robust real-time web applications.
16 | */
17 |
18 | // import Echo from 'laravel-echo';
19 |
20 | // import Pusher from 'pusher-js';
21 | // window.Pusher = Pusher;
22 |
23 | // window.Echo = new Echo({
24 | // broadcaster: 'pusher',
25 | // key: import.meta.env.VITE_PUSHER_APP_KEY,
26 | // cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
27 | // wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
28 | // wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
29 | // wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
30 | // forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
31 | // enabledTransports: ['ws', 'wss'],
32 | // });
33 |
--------------------------------------------------------------------------------
/public/build/assets/DialogModal-9a2b4a3d.js:
--------------------------------------------------------------------------------
1 | import{o as i,c as r,w as n,a as e,A as a,p as d,b as c,u as f}from"./app-9cb26ff6.js";import{X as x}from"./index-afa3307c.js";import{_ as m}from"./Modal-d953ae84.js";const u={class:"px-6 py-4"},h={class:"flex justify-between items-center text-lg font-medium text-slate-900 dark:text-slate-100 space-x-2"},b=["onClick"],p={class:"mt-4 text-sm text-slate-600 dark:text-slate-400"},k={class:"flex flex-row justify-end px-6 py-4 bg-slate-100 dark:bg-slate-900/30 text-right"},y={__name:"DialogModal",props:{show:{type:Boolean,default:!1},maxWidth:{type:String,default:"xl"},closeable:{type:Boolean,default:!1}},emits:["close"],setup(t,{emit:l}){const o=()=>{l("close")};return(s,_)=>(i(),r(m,{show:t.show,"max-width":t.maxWidth,closeable:t.closeable,onClose:o},{default:n(()=>[e("div",u,[e("div",h,[a(s.$slots,"title"),e("button",{class:"inline-flex items-center p-2 border border-slate-200 dark:border-slate-700 text-sm leading-4 font-medium rounded text-slate-500 dark:text-slate-400 bg-white dark:bg-slate-800 hover:text-slate-700 dark:hover:text-slate-300 focus:outline-none focus:bg-slate-50 dark:focus:bg-slate-700 active:bg-slate-50 dark:active:bg-slate-700 transition ease-in-out duration-150",onClick:d(o,["prevent"])},[c(f(x),{class:"w-4 h-auto"})],8,b)]),e("div",p,[a(s.$slots,"content")])]),e("div",k,[a(s.$slots,"footer")])]),_:3},8,["show","max-width","closeable"]))}};export{y as _};
2 |
--------------------------------------------------------------------------------
/tests/Feature/ApiTokenPermissionsTest.php:
--------------------------------------------------------------------------------
1 | markTestSkipped('API support is not enabled.');
19 |
20 | return;
21 | }
22 |
23 | $this->actingAs($user = User::factory()->withPersonalTeam()->create());
24 |
25 | $token = $user->tokens()->create([
26 | 'name' => 'Test Token',
27 | 'token' => Str::random(40),
28 | 'abilities' => ['create', 'read'],
29 | ]);
30 |
31 | $response = $this->put('/user/api-tokens/'.$token->id, [
32 | 'name' => $token->name,
33 | 'permissions' => [
34 | 'delete',
35 | 'missing-permission',
36 | ],
37 | ]);
38 |
39 | $this->assertTrue($user->fresh()->tokens->first()->can('delete'));
40 | $this->assertFalse($user->fresh()->tokens->first()->can('read'));
41 | $this->assertFalse($user->fresh()->tokens->first()->can('missing-permission'));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/build/assets/Index-67a1ca5c.js:
--------------------------------------------------------------------------------
1 | import s from"./ApiTokenManager-bf9fcdb3.js";import{_ as r}from"./AppLayout-706b8ec5.js";import{o as e,c as m,w as a,a as t,t as p,b as l}from"./app-9cb26ff6.js";import"./ActionMessage-dafe95ee.js";import"./ActionSection-bb60ff24.js";import"./SectionTitle-1f89132a.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./Checkbox-97f2cde6.js";import"./ConfirmationModal-8097dc2a.js";import"./Modal-d953ae84.js";import"./DangerButton-db69db22.js";import"./DialogModal-9a2b4a3d.js";import"./index-afa3307c.js";import"./FormSection-fd684e6c.js";import"./InputError-71f77be1.js";import"./InputLabel-ef1a5601.js";import"./PrimaryButton-0fb1f193.js";import"./SecondaryButton-4d541c38.js";import"./SectionBorder-6e176b61.js";import"./TextInput-f97bd710.js";import"./Toast-48e493b9.js";import"./SwitchDarkMode-e6f628a6.js";import"./SwitchLocale-b9e142e8.js";import"./ApplicationLogo-914092fa.js";const n={class:"max-w-7xl mx-auto py-10 sm:px-6 lg:px-8"},z={__name:"Index",props:{tokens:Array,availablePermissions:Array,defaultPermissions:Array},setup(i){return(o,c)=>(e(),m(r,{title:o.lang().label.api_tokens},{title:a(()=>[t("span",null,p(o.lang().label.api_tokens),1)]),default:a(()=>[t("div",null,[t("div",n,[l(s,{tokens:i.tokens,"available-permissions":i.availablePermissions,"default-permissions":i.defaultPermissions},null,8,["tokens","available-permissions","default-permissions"])])])]),_:1},8,["title"]))}};export{z as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/Delete-79d257e4.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as b,m as h,o as d,d as w,j as k,c as C,w as t,b as l,u as a,p as $,e as r,t as o,n as D}from"./app-9cb26ff6.js";import{_ as S}from"./ConfirmationModal-8097dc2a.js";import{_ as y}from"./ActionButton-0ff23640.js";import{_ as B}from"./DangerButton-db69db22.js";import{_ as T}from"./SecondaryButton-4d541c38.js";import{T as j}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const O={__name:"Delete",props:{title:String,role:Object},emits:["open"],setup(f,{emit:u}){const n=f,i=g(!1),s=b({}),_=()=>{var e;s.delete(route("role.destroy",(e=n.role)==null?void 0:e.id),{preserveScroll:!0,onSuccess:()=>c(),onError:()=>null,onFinish:()=>null})},c=()=>{i.value=!1};return(e,p)=>{const v=h("tooltip");return d(),w("div",null,[k((d(),C(y,{variant:"danger",onClick:p[0]||(p[0]=$(m=>(i.value=!0,u("open")),["prevent"]))},{default:t(()=>[l(a(j),{class:"w-4 h-auto"})]),_:1})),[[v,e.lang().label.delete]]),l(S,{show:i.value,onClose:c},{title:t(()=>[r(o(e.lang().label.delete)+" "+o(n.title),1)]),content:t(()=>{var m;return[r(o(e.lang().label.delete_confirm)+" "+o((m=n.role)==null?void 0:m.name)+"? ",1)]}),footer:t(()=>[l(T,{onClick:c},{default:t(()=>[r(o(e.lang().button.cancel),1)]),_:1}),l(B,{class:D(["ml-3",{"opacity-25":a(s).processing}]),disabled:a(s).processing,onClick:_},{default:t(()=>[r(o(e.lang().button.delete)+" "+o(a(s).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{O as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/Delete-a6494205.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as b,m as h,o as p,d as w,j as k,c as C,w as o,b as a,u as l,p as $,e as r,t as s,n as D}from"./app-9cb26ff6.js";import{_ as S}from"./ConfirmationModal-8097dc2a.js";import{_ as y}from"./ActionButton-0ff23640.js";import{_ as B}from"./DangerButton-db69db22.js";import{_ as T}from"./SecondaryButton-4d541c38.js";import{T as j}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const O={__name:"Delete",props:{title:String,user:Object},emits:["open"],setup(d,{emit:f}){const n=d,i=g(!1),t=b({}),_=()=>{var e;t.delete(route("user.destroy",(e=n.user)==null?void 0:e.id),{preserveScroll:!0,onSuccess:()=>c(),onError:()=>null,onFinish:()=>null})},c=()=>{i.value=!1};return(e,u)=>{const v=h("tooltip");return p(),w("div",null,[k((p(),C(y,{variant:"danger",onClick:u[0]||(u[0]=$(m=>(i.value=!0,f("open")),["prevent"]))},{default:o(()=>[a(l(j),{class:"w-4 h-auto"})]),_:1})),[[v,e.lang().label.delete]]),a(S,{show:i.value,onClose:c},{title:o(()=>[r(s(e.lang().label.delete)+" "+s(n.title),1)]),content:o(()=>{var m;return[r(s(e.lang().label.delete_confirm)+" "+s((m=n.user)==null?void 0:m.name)+"? ",1)]}),footer:o(()=>[a(T,{onClick:c},{default:o(()=>[r(s(e.lang().button.cancel),1)]),_:1}),a(B,{class:D(["ml-3",{"opacity-25":l(t).processing}]),disabled:l(t).processing,onClick:_},{default:o(()=>[r(s(e.lang().button.delete)+" "+s(l(t).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{O as default};
2 |
--------------------------------------------------------------------------------
/resources/js/Components/FormSection.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/public/build/assets/Delete-787e6cee.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as b,m as h,o as d,d as w,j as y,c as k,w as o,b as a,u as l,p as C,e as i,t,n as $}from"./app-9cb26ff6.js";import{_ as D}from"./ConfirmationModal-8097dc2a.js";import{_ as S}from"./ActionButton-0ff23640.js";import{_ as B}from"./DangerButton-db69db22.js";import{_ as T}from"./SecondaryButton-4d541c38.js";import{T as j}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const O={__name:"Delete",props:{title:String,activity:Object},emits:["open"],setup(f,{emit:u}){const r=f,n=g(!1),s=b({}),_=()=>{var e;s.delete(route("activity.destroy",(e=r.activity)==null?void 0:e.id),{preserveScroll:!0,onSuccess:()=>c(),onError:()=>null,onFinish:()=>null})},c=()=>{n.value=!1};return(e,p)=>{const v=h("tooltip");return d(),w("div",null,[y((d(),k(S,{variant:"danger",onClick:p[0]||(p[0]=C(m=>(n.value=!0,u("open")),["prevent"]))},{default:o(()=>[a(l(j),{class:"w-4 h-auto"})]),_:1})),[[v,e.lang().label.delete]]),a(D,{show:n.value,onClose:c},{title:o(()=>[i(t(e.lang().label.delete)+" "+t(r.title),1)]),content:o(()=>{var m;return[i(t(e.lang().label.delete_confirm)+" "+t((m=r.activity)==null?void 0:m.description)+"? ",1)]}),footer:o(()=>[a(T,{onClick:c},{default:o(()=>[i(t(e.lang().button.cancel),1)]),_:1}),a(B,{class:$(["ml-3",{"opacity-25":l(s).processing}]),disabled:l(s).processing,onClick:_},{default:o(()=>[i(t(e.lang().button.delete)+" "+t(l(s).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{O as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/DeleteBulk-6f56dab6.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as h,q as w,m as k,o as f,d as C,j as B,c as D,w as s,b as n,u as r,p as I,e as i,t as e,n as S}from"./app-9cb26ff6.js";import{_ as $}from"./ConfirmationModal-8097dc2a.js";import{_ as m}from"./DangerButton-db69db22.js";import{_ as y}from"./SecondaryButton-4d541c38.js";import{T as E}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const z={__name:"DeleteBulk",props:{title:String,selectedId:Object},emits:["close"],setup(p,{emit:_}){const o=p,a=g(!1),t=h({id:[]});w(()=>{a&&(t.id=o.selectedId)});const v=()=>{t.post(route("role.destroy-bulk"),{preserveScroll:!0,onSuccess:()=>{c(),_("close")},onError:()=>null,onFinish:()=>null})},c=()=>{a.value=!1};return(l,u)=>{const b=k("tooltip");return f(),C("div",null,[B((f(),D(m,{class:"rounded-none",onClick:u[0]||(u[0]=I(d=>a.value=!0,["prevent"]))},{default:s(()=>[n(r(E),{class:"w-4 h-auto"})]),_:1})),[[b,l.lang().label.delete_selected]]),n($,{show:a.value,onClose:c},{title:s(()=>[i(e(l.lang().label.delete_selected)+" "+e(o.title),1)]),content:s(()=>{var d;return[i(e(l.lang().label.delete_confirm)+" "+e((d=o.selectedId)==null?void 0:d.length)+" "+e(o.title)+"? ",1)]}),footer:s(()=>[n(y,{onClick:c},{default:s(()=>[i(e(l.lang().button.cancel),1)]),_:1}),n(m,{class:S(["ml-3",{"opacity-25":r(t).processing}]),disabled:r(t).processing,onClick:v},{default:s(()=>[i(e(l.lang().button.delete)+" "+e(r(t).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{z as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/DeleteBulk-896ff391.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as h,q as w,m as k,o as f,d as C,j as y,c as B,w as t,b as n,u as r,p as D,e as i,t as e,n as I}from"./app-9cb26ff6.js";import{_ as S}from"./ConfirmationModal-8097dc2a.js";import{_ as m}from"./DangerButton-db69db22.js";import{_ as $}from"./SecondaryButton-4d541c38.js";import{T as E}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const z={__name:"DeleteBulk",props:{title:String,selectedId:Object},emits:["close"],setup(p,{emit:_}){const o=p,a=g(!1),s=h({id:[]});w(()=>{a&&(s.id=o.selectedId)});const v=()=>{s.post(route("activity.destroy-bulk"),{preserveScroll:!0,onSuccess:()=>{c(),_("close")},onError:()=>null,onFinish:()=>null})},c=()=>{a.value=!1};return(l,u)=>{const b=k("tooltip");return f(),C("div",null,[y((f(),B(m,{class:"rounded-none",onClick:u[0]||(u[0]=D(d=>a.value=!0,["prevent"]))},{default:t(()=>[n(r(E),{class:"w-4 h-auto"})]),_:1})),[[b,l.lang().label.delete_selected]]),n(S,{show:a.value,onClose:c},{title:t(()=>[i(e(l.lang().label.delete_selected)+" "+e(o.title),1)]),content:t(()=>{var d;return[i(e(l.lang().label.delete_confirm)+" "+e((d=o.selectedId)==null?void 0:d.length)+" "+e(o.title)+"? ",1)]}),footer:t(()=>[n($,{onClick:c},{default:t(()=>[i(e(l.lang().button.cancel),1)]),_:1}),n(m,{class:I(["ml-3",{"opacity-25":r(s).processing}]),disabled:r(s).processing,onClick:v},{default:t(()=>[i(e(l.lang().button.delete)+" "+e(r(s).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{z as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/DeleteBulk-d065b9a7.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as h,q as w,m as k,o as f,d as C,j as B,c as D,w as s,b as n,u as r,p as I,e as i,t as e,n as S}from"./app-9cb26ff6.js";import{_ as $}from"./ConfirmationModal-8097dc2a.js";import{_ as m}from"./DangerButton-db69db22.js";import{_ as y}from"./SecondaryButton-4d541c38.js";import{T as E}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const z={__name:"DeleteBulk",props:{title:String,selectedId:Object},emits:["close"],setup(p,{emit:_}){const o=p,a=g(!1),t=h({id:[]});w(()=>{a&&(t.id=o.selectedId)});const v=()=>{t.post(route("user.destroy-bulk"),{preserveScroll:!0,onSuccess:()=>{c(),_("close")},onError:()=>null,onFinish:()=>null})},c=()=>{a.value=!1};return(l,u)=>{const b=k("tooltip");return f(),C("div",null,[B((f(),D(m,{class:"rounded-none",onClick:u[0]||(u[0]=I(d=>a.value=!0,["prevent"]))},{default:s(()=>[n(r(E),{class:"w-4 h-auto"})]),_:1})),[[b,l.lang().label.delete_selected]]),n($,{show:a.value,onClose:c},{title:s(()=>[i(e(l.lang().label.delete_selected)+" "+e(o.title),1)]),content:s(()=>{var d;return[i(e(l.lang().label.delete_confirm)+" "+e((d=o.selectedId)==null?void 0:d.length)+" "+e(o.title)+"? ",1)]}),footer:s(()=>[n(y,{onClick:c},{default:s(()=>[i(e(l.lang().button.cancel),1)]),_:1}),n(m,{class:S(["ml-3",{"opacity-25":r(t).processing}]),disabled:r(t).processing,onClick:v},{default:s(()=>[i(e(l.lang().button.delete)+" "+e(r(t).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{z as default};
2 |
--------------------------------------------------------------------------------
/resources/js/Layouts/AppLayout.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/public/build/assets/DeleteBulk-f59ba241.js:
--------------------------------------------------------------------------------
1 | import{r as g,v as h,q as w,m as k,o as m,d as C,j as B,c as D,w as s,b as n,u as r,p as I,e as i,t as e,n as S}from"./app-9cb26ff6.js";import{_ as $}from"./ConfirmationModal-8097dc2a.js";import{_ as p}from"./DangerButton-db69db22.js";import{_ as y}from"./SecondaryButton-4d541c38.js";import{T as E}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const z={__name:"DeleteBulk",props:{title:String,selectedId:Object},emits:["close"],setup(f,{emit:_}){const l=f,a=g(!1),t=h({id:[]});w(()=>{a&&(t.id=l.selectedId)});const v=()=>{t.post(route("permission.destroy-bulk"),{preserveScroll:!0,onSuccess:()=>{c(),_("close")},onError:()=>null,onFinish:()=>null})},c=()=>{a.value=!1};return(o,u)=>{const b=k("tooltip");return m(),C("div",null,[B((m(),D(p,{class:"rounded-none",onClick:u[0]||(u[0]=I(d=>a.value=!0,["prevent"]))},{default:s(()=>[n(r(E),{class:"w-4 h-auto"})]),_:1})),[[b,o.lang().label.delete_selected]]),n($,{show:a.value,onClose:c},{title:s(()=>[i(e(o.lang().label.delete_selected)+" "+e(l.title),1)]),content:s(()=>{var d;return[i(e(o.lang().label.delete_confirm)+" "+e((d=l.selectedId)==null?void 0:d.length)+" "+e(l.title)+"? ",1)]}),footer:s(()=>[n(y,{onClick:c},{default:s(()=>[i(e(o.lang().button.cancel),1)]),_:1}),n(p,{class:S(["ml-3",{"opacity-25":r(t).processing}]),disabled:r(t).processing,onClick:v},{default:s(()=>[i(e(o.lang().button.delete)+" "+e(r(t).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{z as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/Delete-9c183e52.js:
--------------------------------------------------------------------------------
1 | import{r as b,v as g,m as h,o as d,d as w,j as k,c as C,w as o,b as l,u as n,p as $,e as t,t as s,a as B,n as D}from"./app-9cb26ff6.js";import{_ as S}from"./ConfirmationModal-8097dc2a.js";import{_ as y}from"./ActionButton-0ff23640.js";import{_ as N}from"./DangerButton-db69db22.js";import{_ as T}from"./SecondaryButton-4d541c38.js";import{T as V}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const j={class:"font-black"},A={__name:"Delete",props:{title:String,permission:Object},emits:["open"],setup(f,{emit:u}){const r=f,i=b(!1),a=g({}),_=()=>{var e;a.delete(route("permission.destroy",(e=r.permission)==null?void 0:e.id),{preserveScroll:!0,onSuccess:()=>c(),onError:()=>null,onFinish:()=>null})},c=()=>{i.value=!1};return(e,p)=>{const v=h("tooltip");return d(),w("div",null,[k((d(),C(y,{variant:"danger",onClick:p[0]||(p[0]=$(m=>(i.value=!0,u("open")),["prevent"]))},{default:o(()=>[l(n(V),{class:"w-4 h-auto"})]),_:1})),[[v,e.lang().label.delete]]),l(S,{show:i.value,onClose:c},{title:o(()=>[t(s(e.lang().label.delete)+" "+s(r.title),1)]),content:o(()=>{var m;return[t(s(e.lang().label.delete_confirm)+" ",1),B("span",j,s((m=r.permission)==null?void 0:m.name),1),t("? ")]}),footer:o(()=>[l(T,{onClick:c},{default:o(()=>[t(s(e.lang().button.cancel),1)]),_:1}),l(N,{class:D(["ml-3",{"opacity-25":n(a).processing}]),disabled:n(a).processing,onClick:_},{default:o(()=>[t(s(e.lang().button.delete)+" "+s(n(a).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{A as default};
2 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | configureRateLimiting();
28 |
29 | $this->routes(function () {
30 | Route::middleware('api')
31 | ->prefix('api')
32 | ->group(base_path('routes/api.php'));
33 |
34 | Route::middleware('web')
35 | ->group(base_path('routes/web.php'));
36 | });
37 | }
38 |
39 | /**
40 | * Configure the rate limiters for the application.
41 | */
42 | protected function configureRateLimiting(): void
43 | {
44 | RateLimiter::for('api', function (Request $request) {
45 | return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
46 | });
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/Providers/FortifyServiceProvider.php:
--------------------------------------------------------------------------------
1 | email;
37 |
38 | return Limit::perMinute(5)->by($email.$request->ip());
39 | });
40 |
41 | RateLimiter::for('two-factor', function (Request $request) {
42 | return Limit::perMinute(5)->by($request->session()->get('login.id'));
43 | });
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/public/build/assets/Permission-e0ed2ecc.js:
--------------------------------------------------------------------------------
1 | import{_ as k}from"./DialogModal-9a2b4a3d.js";import{_ as C}from"./SecondaryButton-4d541c38.js";import{r as D,m as N,o as n,d as l,a as i,j as B,e as f,t as o,b as h,w as c,F as w,f as x,n as S}from"./app-9cb26ff6.js";import"./index-afa3307c.js";import"./Modal-d953ae84.js";const V={class:"space-y-2"},$={class:"font-bold text-primary capitalize"},j={class:"flex flex-wrap gap-4"},L={__name:"Permission",props:{title:String,caption:{type:String,default:null},permissions:Object},setup(b){var g;const a=b,m=D(!1),r=[];let u=null;(g=a.permissions)==null||g.forEach(e=>{const t=e.name.split(" ")[0],p=e.name.split(" ")[1];if(u!==t)u=t,r.push({group:u,data:[{name:p}]});else{const s=r.findIndex(d=>d.group===t);s!==-1&&r[s].data.push({name:p})}});const _=()=>{m.value=!1};return(e,t)=>{const p=N("tooltip");return n(),l("div",null,[i("div",null,[B((n(),l("p",{class:"text-primary underline cursor-pointer w-fit",onClick:t[0]||(t[0]=s=>m.value=!0)},[f(o(a.title),1)])),[[p,e.lang().label.show_permission]])]),h(k,{show:m.value,onClose:_,"max-width":"md"},{title:c(()=>[f(o(e.lang().label.permission)+" "+o(a.caption?a.caption:a.title),1)]),content:c(()=>[i("div",V,[(n(),l(w,null,x(r,(s,d)=>i("div",{class:"mt-2",key:d},[i("p",$,o(s.group),1),i("div",j,[(n(!0),l(w,null,x(s.data,(v,y)=>(n(),l("p",{key:y,class:S([v.name=="delete"?"text-red-500 font-semibold":"","mt-1 mb-4"])},o(v.name),3))),128))])])),64))])]),footer:c(()=>[h(C,{onClick:_},{default:c(()=>[f(o(e.lang().button.close),1)]),_:1})]),_:1},8,["show"])])}}};export{L as default};
2 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php:
--------------------------------------------------------------------------------
1 | text('two_factor_secret')
17 | ->after('password')
18 | ->nullable();
19 |
20 | $table->text('two_factor_recovery_codes')
21 | ->after('two_factor_secret')
22 | ->nullable();
23 |
24 | if (Fortify::confirmsTwoFactorAuthentication()) {
25 | $table->timestamp('two_factor_confirmed_at')
26 | ->after('two_factor_recovery_codes')
27 | ->nullable();
28 | }
29 | });
30 | }
31 |
32 | /**
33 | * Reverse the migrations.
34 | */
35 | public function down(): void
36 | {
37 | Schema::table('users', function (Blueprint $table) {
38 | $table->dropColumn(array_merge([
39 | 'two_factor_secret',
40 | 'two_factor_recovery_codes',
41 | ], Fortify::confirmsTwoFactorAuthentication() ? [
42 | 'two_factor_confirmed_at',
43 | ] : []));
44 | });
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/public/build/assets/ConfirmationModal-8097dc2a.js:
--------------------------------------------------------------------------------
1 | import{_ as i}from"./Modal-d953ae84.js";import{o as r,c,w as n,a as t,A as o}from"./app-9cb26ff6.js";const d={class:"bg-white dark:bg-slate-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4"},m={class:"sm:flex sm:items-start"},h=t("div",{class:"mx-auto shrink-0 flex items-center justify-center h-12 w-12 rounded bg-rose-100 sm:mx-0 sm:h-10 sm:w-10"},[t("svg",{class:"h-6 w-6 text-rose-600 dark:text-rose-400",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"})])],-1),x={class:"mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"},f={class:"text-lg font-medium text-slate-900 dark:text-slate-100"},w={class:"mt-4 text-sm text-slate-600 dark:text-slate-400"},_={class:"flex flex-row justify-end px-6 py-4 bg-slate-100 dark:bg-slate-800 text-right"},v={__name:"ConfirmationModal",props:{show:{type:Boolean,default:!1},maxWidth:{type:String,default:"2xl"},closeable:{type:Boolean,default:!1}},emits:["close"],setup(s,{emit:a}){const l=()=>{a("close")};return(e,p)=>(r(),c(i,{show:s.show,"max-width":s.maxWidth,closeable:s.closeable,onClose:l},{default:n(()=>[t("div",d,[t("div",m,[h,t("div",x,[t("h3",f,[o(e.$slots,"title")]),t("div",w,[o(e.$slots,"content")])])])]),t("div",_,[o(e.$slots,"footer")])]),_:3},8,["show","max-width","closeable"]))}};export{v as _};
2 |
--------------------------------------------------------------------------------
/resources/js/app.js:
--------------------------------------------------------------------------------
1 | import "./bootstrap";
2 | import "../css/app.css";
3 | import "floating-vue/dist/style.css";
4 |
5 | import { createApp, h } from "vue";
6 | import { createInertiaApp } from "@inertiajs/vue3";
7 | import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";
8 | import { ZiggyVue } from "ziggy-js";
9 | import { usePage } from "@inertiajs/vue3";
10 | import FloatingVue from "floating-vue";
11 | import Vue3Lottie from "vue3-lottie";
12 | import "vue3-lottie/dist/style.css";
13 | import JsonViewer from "vue-json-viewer";
14 | import GlobalMixin from "./Mixins/global";
15 |
16 | const pages = import.meta.glob("./Pages/**/*.vue");
17 |
18 | createInertiaApp({
19 | title: (title) =>
20 | title
21 | ? `${title} | ${usePage().props?.app?.setting?.short_name || "Laravel"}`
22 | : `${usePage().props?.app?.setting?.short_name || "Laravel"}`,
23 | resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, pages),
24 | setup({ el, App, props, plugin }) {
25 | // ✅ Deklarasi `vueApp` terlebih dahulu sebelum mengakses `config.globalProperties`
26 | const vueApp = createApp({ render: () => h(App, props) });
27 |
28 | // ✅ Gunakan semua plugin & mixin sebelum mounting
29 | return vueApp
30 | .use(plugin)
31 | .use(ZiggyVue)
32 | .use(FloatingVue)
33 | .use(Vue3Lottie)
34 | .use(JsonViewer)
35 | .mixin(GlobalMixin)
36 | .mount(el);
37 | },
38 | progress: {
39 | color: "#00ba7c",
40 | },
41 | });
42 |
--------------------------------------------------------------------------------
/resources/views/app.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ config('app.name', 'Laravel') }}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
25 | @routes
26 | @vite(['resources/js/app.js', "resources/js/Pages/{$page['component']}.vue"])
27 | @inertiaHead
28 |
29 |
30 | @inertia
31 |
32 |
33 |
--------------------------------------------------------------------------------
/resources/js/Pages/Activity/Properties.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
39 |
40 |
--------------------------------------------------------------------------------
/database/seeders/RoleSeeder.php:
--------------------------------------------------------------------------------
1 | 'superadmin',
18 | 'guard_name' => 'web',
19 | ]);
20 | $superadmin->givePermissionTo([
21 | 'user delete',
22 | 'user update',
23 | 'user read',
24 | 'user create',
25 | 'role delete',
26 | 'role update',
27 | 'role read',
28 | 'role create',
29 | 'permission delete',
30 | 'permission update',
31 | 'permission read',
32 | 'permission create',
33 | 'setting read',
34 | 'activity read',
35 | 'activity delete',
36 | ]);
37 | $admin = Role::create([
38 | 'name' => 'admin',
39 | 'guard_name' => 'web',
40 | ]);
41 | $admin->givePermissionTo([
42 | 'user delete',
43 | 'user update',
44 | 'user read',
45 | 'user create',
46 | 'role read',
47 | 'permission read',
48 | ]);
49 | $operator = Role::create([
50 | 'name' => 'operator',
51 | 'guard_name' => 'web',
52 | ]);
53 |
54 | $operator->givePermissionTo([
55 | 'user read',
56 | 'role read',
57 | 'permission read',
58 | ]);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/config/activitylog.php:
--------------------------------------------------------------------------------
1 | env('ACTIVITY_LOGGER_ENABLED', true),
9 |
10 | /*
11 | * When the clean-command is executed, all recording activities older than
12 | * the number of days specified here will be deleted.
13 | */
14 | 'delete_records_older_than_days' => 365,
15 |
16 | /*
17 | * If no log name is passed to the activity() helper
18 | * we use this default log name.
19 | */
20 | 'default_log_name' => 'system',
21 |
22 | /*
23 | * You can specify an auth driver here that gets user models.
24 | * If this is null we'll use the current Laravel auth driver.
25 | */
26 | 'default_auth_driver' => null,
27 |
28 | /*
29 | * If set to true, the subject returns soft deleted models.
30 | */
31 | 'subject_returns_soft_deleted_models' => false,
32 |
33 | /*
34 | * This model will be used to log activity.
35 | * It should implement the Spatie\Activitylog\Contracts\Activity interface
36 | * and extend Illuminate\Database\Eloquent\Model.
37 | */
38 | 'activity_model' => \Spatie\Activitylog\Models\Activity::class,
39 |
40 | /*
41 | * This is the name of the table that will be created by the migration and
42 | * used by the Activity model shipped with this package.
43 | */
44 | 'table_name' => 'activity_log',
45 |
46 | /*
47 | * This is the database connection that will be used by the migration and
48 | * the Activity model shipped with this package. In case it's not set
49 | * Laravel's database.default will be used instead.
50 | */
51 | 'database_connection' => env('ACTIVITY_LOGGER_DB_CONNECTION'),
52 | ];
53 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Bcrypt Options
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may specify the configuration options that should be used when
26 | | passwords are hashed using the Bcrypt algorithm. This will allow you
27 | | to control the amount of time it takes to hash the given password.
28 | |
29 | */
30 |
31 | 'bcrypt' => [
32 | 'rounds' => env('BCRYPT_ROUNDS', 10),
33 | ],
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Argon Options
38 | |--------------------------------------------------------------------------
39 | |
40 | | Here you may specify the configuration options that should be used when
41 | | passwords are hashed using the Argon algorithm. These will allow you
42 | | to control the amount of time it takes to hash the given password.
43 | |
44 | */
45 |
46 | 'argon' => [
47 | 'memory' => 65536,
48 | 'threads' => 1,
49 | 'time' => 4,
50 | ],
51 |
52 | ];
53 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/tests/Feature/UpdatePasswordTest.php:
--------------------------------------------------------------------------------
1 | actingAs($user = User::factory()->create());
17 |
18 | $response = $this->put('/user/password', [
19 | 'current_password' => 'password',
20 | 'password' => 'new-password',
21 | 'password_confirmation' => 'new-password',
22 | ]);
23 |
24 | $this->assertTrue(Hash::check('new-password', $user->fresh()->password));
25 | }
26 |
27 | public function test_current_password_must_be_correct(): void
28 | {
29 | $this->actingAs($user = User::factory()->create());
30 |
31 | $response = $this->put('/user/password', [
32 | 'current_password' => 'wrong-password',
33 | 'password' => 'new-password',
34 | 'password_confirmation' => 'new-password',
35 | ]);
36 |
37 | $response->assertSessionHasErrors();
38 |
39 | $this->assertTrue(Hash::check('password', $user->fresh()->password));
40 | }
41 |
42 | public function test_new_passwords_must_match(): void
43 | {
44 | $this->actingAs($user = User::factory()->create());
45 |
46 | $response = $this->put('/user/password', [
47 | 'current_password' => 'password',
48 | 'password' => 'new-password',
49 | 'password_confirmation' => 'wrong-password',
50 | ]);
51 |
52 | $response->assertSessionHasErrors();
53 |
54 | $this->assertTrue(Hash::check('password', $user->fresh()->password));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/Feature/RegistrationTest.php:
--------------------------------------------------------------------------------
1 | markTestSkipped('Registration support is not enabled.');
19 |
20 | return;
21 | }
22 |
23 | $response = $this->get('/register');
24 |
25 | $response->assertStatus(200);
26 | }
27 |
28 | public function test_registration_screen_cannot_be_rendered_if_support_is_disabled(): void
29 | {
30 | if (Features::enabled(Features::registration())) {
31 | $this->markTestSkipped('Registration support is enabled.');
32 |
33 | return;
34 | }
35 |
36 | $response = $this->get('/register');
37 |
38 | $response->assertStatus(404);
39 | }
40 |
41 | public function test_new_users_can_register(): void
42 | {
43 | if (! Features::enabled(Features::registration())) {
44 | $this->markTestSkipped('Registration support is not enabled.');
45 |
46 | return;
47 | }
48 |
49 | $response = $this->post('/register', [
50 | 'name' => 'Test User',
51 | 'email' => 'test@example.com',
52 | 'password' => 'password',
53 | 'password_confirmation' => 'password',
54 | 'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature(),
55 | ]);
56 |
57 | $this->assertAuthenticated();
58 | $response->assertRedirect(RouteServiceProvider::HOME);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/public/build/assets/Create-1f78ecde.js:
--------------------------------------------------------------------------------
1 | import{r as b,v,o as h,d as w,b as s,w as l,u as a,a as m,t as n,p as d,e as c,n as k}from"./app-9cb26ff6.js";import{_ as C}from"./DialogModal-9a2b4a3d.js";import{_ as $}from"./InputError-71f77be1.js";import{_ as y}from"./InputLabel-ef1a5601.js";import{_ as f}from"./PrimaryButton-0fb1f193.js";import{_ as S}from"./SecondaryButton-4d541c38.js";import{_ as V}from"./TextInput-f97bd710.js";import{P as B}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const N={class:"hidden md:block"},E=["onSubmit"],M={class:"space-y-1"},x={__name:"Create",props:{title:String},setup(_){const g=_,t=b(!1),e=v({name:"",guard_name:"web"}),u=()=>{e.post(route("permission.store"),{preserveScroll:!0,onSuccess:()=>i(),onError:()=>null,onFinish:()=>null})},i=()=>{t.value=!1,e.errors={},e.reset()};return(o,r)=>(h(),w("div",null,[s(f,{class:"flex rounded-none items-center justify-start gap-2",onClick:r[0]||(r[0]=d(p=>t.value=!0,["prevent"]))},{default:l(()=>[s(a(B),{class:"w-4 h-auto"}),m("span",N,n(o.lang().button.add),1)]),_:1}),s(C,{show:t.value,onClose:i},{title:l(()=>[c(n(o.lang().label.add)+" "+n(g.title),1)]),content:l(()=>[m("form",{class:"space-y-2",onSubmit:d(u,["prevent"])},[m("div",M,[s(y,{for:"name",value:o.lang().label.name},null,8,["value"]),s(V,{id:"name",modelValue:a(e).name,"onUpdate:modelValue":r[1]||(r[1]=p=>a(e).name=p),type:"text",class:"block w-full",autocomplete:"name",placeholder:o.lang().placeholder.permission_name,error:a(e).errors.name},null,8,["modelValue","placeholder","error"]),s($,{message:a(e).errors.name},null,8,["message"])])],40,E)]),footer:l(()=>[s(S,{onClick:i},{default:l(()=>[c(n(o.lang().button.cancel),1)]),_:1}),s(f,{class:k(["ml-3",{"opacity-25":a(e).processing}]),disabled:a(e).processing,onClick:u},{default:l(()=>[c(n(o.lang().button.save)+" "+n(a(e).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])]))}};export{x as default};
2 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/public/build/assets/ConfirmPassword-534de2b7.js:
--------------------------------------------------------------------------------
1 | import{v as d,r as c,o as f,d as u,b as a,u as o,X as _,w as t,a as e,t as l,n as w,e as b,p as g,F as h}from"./app-9cb26ff6.js";import{_ as v}from"./AuthenticationCard-4227316f.js";import{_ as x}from"./AuthenticationCardLogo-a2386df2.js";import{_ as y}from"./InputError-71f77be1.js";import{_ as V}from"./InputLabel-ef1a5601.js";import{_ as $}from"./PrimaryButton-0fb1f193.js";import{_ as k}from"./TextInput-f97bd710.js";import"./SwitchLocale-b9e142e8.js";import"./SwitchDarkMode-e6f628a6.js";import"./index-afa3307c.js";import"./ApplicationLogo-914092fa.js";import"./_plugin-vue_export-helper-c27b6911.js";const B={class:"flex flex-col mb-4"},C={class:"text-primary font-semibold text-xl"},F={class:"text-slate-400"},N=["onSubmit"],S={class:"flex justify-end mt-4"},H={__name:"ConfirmPassword",setup(I){const s=d({password:""}),n=c(null),m=()=>{s.post(route("password.confirm"),{onFinish:()=>{s.reset(),n.value.focus()}})};return(r,i)=>(f(),u(h,null,[a(o(_),{title:"lang().label.secure_area"}),a(v,null,{logo:t(()=>[a(x)]),default:t(()=>[e("div",B,[e("h2",C,l(r.lang().label.confirm_password),1),e("small",F,l(r.lang().label.confirm_password_caption),1)]),e("form",{onSubmit:g(m,["prevent"])},[e("div",null,[a(V,{for:"password",value:r.lang().label.password},null,8,["value"]),a(k,{id:"password",ref_key:"passwordInput",ref:n,modelValue:o(s).password,"onUpdate:modelValue":i[0]||(i[0]=p=>o(s).password=p),type:"password",class:"mt-1 block w-full",required:"",placeholder:r.lang().placeholder.password,error:o(s).errors.password,autocomplete:"current-password",autofocus:""},null,8,["modelValue","placeholder","error"]),a(y,{class:"mt-2",message:o(s).errors.password},null,8,["message"])]),e("div",S,[a($,{class:w(["ml-4",{"opacity-25":o(s).processing}]),disabled:o(s).processing},{default:t(()=>[b(l(r.lang().button.confirm)+" "+l(o(s).processing?"...":""),1)]),_:1},8,["class","disabled"])])],40,N)]),_:1})],64))}};export{H as default};
2 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class);
50 |
51 | $response = $kernel->handle(
52 | $request = Request::capture()
53 | )->send();
54 |
55 | $kernel->terminate($request, $response);
56 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Api/UserController.php:
--------------------------------------------------------------------------------
1 | json([
16 | 'data' => User::with('roles')->find(auth()->user()->id),
17 | 'message' => "Data user loged in",
18 | 'status' => Response::HTTP_OK,
19 | 'access_token' => "",
20 | 'token_type' => 'Bearer'
21 | ]);
22 | }
23 |
24 | public function updatePassword(Request $request){
25 | try {
26 | $user = User::find(auth()->user()->id);
27 | if (!Hash::check($request->password, $user->password))
28 | {
29 | return response()
30 | ->json(['message' => 'Unauthorized'], Response::HTTP_UNAUTHORIZED);
31 | }
32 | $user->update([
33 | 'password' => Hash::make($request->new_password)
34 | ]);
35 | return response()->json([
36 | 'data' => User::with('roles')->find(auth()->user()->id),
37 | 'message' => "Data user loged in",
38 | 'status' => Response::HTTP_OK,
39 | 'access_token' => "",
40 | 'token_type' => 'Bearer'
41 | ]);
42 | } catch (\Throwable $th) {
43 | return response()->json([
44 | 'data' => [],
45 | 'message' => $th->getMessage(),
46 | 'status' => $th->getCode(),
47 | 'access_token' => "",
48 | 'token_type' => 'Bearer'
49 | ], Response::HTTP_INTERNAL_SERVER_ERROR);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Actions/Fortify/UpdateUserProfileInformation.php:
--------------------------------------------------------------------------------
1 | $input
17 | */
18 | public function update(User $user, array $input): void
19 | {
20 | Validator::make($input, [
21 | 'name' => ['required', 'string', 'max:255'],
22 | 'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
23 | 'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
24 | ])->validateWithBag('updateProfileInformation');
25 |
26 | if (isset($input['photo'])) {
27 | $user->updateProfilePhoto($input['photo']);
28 | }
29 |
30 | if ($input['email'] !== $user->email &&
31 | $user instanceof MustVerifyEmail) {
32 | $this->updateVerifiedUser($user, $input);
33 | } else {
34 | $user->forceFill([
35 | 'name' => $input['name'],
36 | 'email' => $input['email'],
37 | ])->save();
38 | }
39 | }
40 |
41 | /**
42 | * Update the given verified user's profile information.
43 | *
44 | * @param array $input
45 | */
46 | protected function updateVerifiedUser(User $user, array $input): void
47 | {
48 | $user->forceFill([
49 | 'name' => $input['name'],
50 | 'email' => $input['email'],
51 | 'email_verified_at' => null,
52 | ])->save();
53 |
54 | $user->sendEmailVerificationNotification();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/resources/js/Components/DialogModal.vue:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
34 |
35 |
38 |
39 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/public/build/assets/ForgotPassword-3b3afe78.js:
--------------------------------------------------------------------------------
1 | import{v as p,o as n,d,b as a,u as s,X as _,w as r,a as o,t as l,g as f,n as g,e as b,p as h,F as w}from"./app-9cb26ff6.js";import{_ as v}from"./AuthenticationCard-4227316f.js";import{_ as x}from"./AuthenticationCardLogo-a2386df2.js";import{_ as V}from"./InputError-71f77be1.js";import{_ as k}from"./InputLabel-ef1a5601.js";import{_ as y}from"./PrimaryButton-0fb1f193.js";import{_ as $}from"./TextInput-f97bd710.js";import"./SwitchLocale-b9e142e8.js";import"./SwitchDarkMode-e6f628a6.js";import"./index-afa3307c.js";import"./ApplicationLogo-914092fa.js";import"./_plugin-vue_export-helper-c27b6911.js";const N={class:"flex flex-col mb-4"},S={class:"text-primary font-semibold text-xl"},B={class:"text-slate-400"},C={key:0,class:"mb-4 font-medium text-sm text-green-600 dark:text-green-400"},F=["onSubmit"],j={class:"flex items-center justify-end mt-4"},I={__name:"ForgotPassword",props:{status:String},setup(i){const e=p({email:""}),c=()=>{e.post(route("password.email"))};return(t,m)=>(n(),d(w,null,[a(s(_),{title:t.lang().label.forgot_password},null,8,["title"]),a(v,null,{logo:r(()=>[a(x)]),default:r(()=>[o("div",N,[o("h2",S,l(t.lang().label.forgot_password),1),o("small",B,l(t.lang().label.forgot_password_caption),1)]),i.status?(n(),d("div",C,l(i.status),1)):f("",!0),o("form",{onSubmit:h(c,["prevent"])},[o("div",null,[a(k,{for:"email",value:t.lang().label.email},null,8,["value"]),a($,{id:"email",modelValue:s(e).email,"onUpdate:modelValue":m[0]||(m[0]=u=>s(e).email=u),type:"email",class:"mt-1 block w-full",required:"",autofocus:"",autocomplete:"username",placeholder:t.lang().placeholder.email,error:s(e).errors.email},null,8,["modelValue","placeholder","error"]),a(V,{class:"mt-2",message:s(e).errors.email},null,8,["message"])]),o("div",j,[a(y,{class:g({"opacity-25":s(e).processing}),disabled:s(e).processing},{default:r(()=>[b(l(t.lang().button.email_password_reset_link)+" "+l(s(e).processing?"...":""),1)]),_:1},8,["class","disabled"])])],40,F)]),_:1})],64))}};export{I as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/Show-c2090c6a.js:
--------------------------------------------------------------------------------
1 | import{_ as p}from"./AppLayout-706b8ec5.js";import c from"./DeleteUserForm-a3ec2a2d.js";import l from"./LogoutOtherBrowserSessionsForm-923776ce.js";import{S as r}from"./SectionBorder-6e176b61.js";import u from"./TwoFactorAuthenticationForm-c05a2355.js";import f from"./UpdatePasswordForm-e7555950.js";import d from"./UpdateProfileInformationForm-7c63f334.js";import{o as e,c as _,w as n,a as i,t as g,d as s,b as t,g as a,F as h}from"./app-9cb26ff6.js";import"./Toast-48e493b9.js";import"./index-afa3307c.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./SwitchDarkMode-e6f628a6.js";import"./SwitchLocale-b9e142e8.js";import"./ApplicationLogo-914092fa.js";import"./ActionSection-bb60ff24.js";import"./SectionTitle-1f89132a.js";import"./DangerButton-db69db22.js";import"./DialogModal-9a2b4a3d.js";import"./Modal-d953ae84.js";import"./InputError-71f77be1.js";import"./SecondaryButton-4d541c38.js";import"./TextInput-f97bd710.js";import"./ActionMessage-dafe95ee.js";import"./PrimaryButton-0fb1f193.js";import"./InputLabel-ef1a5601.js";import"./FormSection-fd684e6c.js";const $={class:"max-w-7xl mx-auto py-10 sm:px-6 lg:px-8"},w={key:0},k={key:1},y={key:2},R={__name:"Show",props:{confirmsTwoFactorAuthentication:Boolean,sessions:Array},setup(m){return(o,B)=>(e(),_(p,{title:o.lang().label.profile},{title:n(()=>[i("span",null,g(o.lang().label.profile),1)]),default:n(()=>[i("div",null,[i("div",$,[o.$page.props.jetstream.canUpdateProfileInformation?(e(),s("div",w,[t(d,{user:o.$page.props.auth.user},null,8,["user"]),t(r)])):a("",!0),o.$page.props.jetstream.canUpdatePassword?(e(),s("div",k,[t(f,{class:"mt-10 sm:mt-0"}),t(r)])):a("",!0),o.$page.props.jetstream.canManageTwoFactorAuthentication?(e(),s("div",y,[t(u,{"requires-confirmation":m.confirmsTwoFactorAuthentication,class:"mt-10 sm:mt-0"},null,8,["requires-confirmation"]),t(r)])):a("",!0),t(l,{sessions:m.sessions,class:"mt-10 sm:mt-0"},null,8,["sessions"]),o.$page.props.jetstream.hasAccountDeletionFeatures?(e(),s(h,{key:3},[t(r),t(c,{class:"mt-10 sm:mt-0"})],64)):a("",!0)])])]),_:1},8,["title"]))}};export{R as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/Modal-d953ae84.js:
--------------------------------------------------------------------------------
1 | import{i as x,E as w,G as y,z as f,o as v,c as h,b as o,w as l,j as n,a,T as c,k as i,n as p,u as b,A as k,g,Q as _}from"./app-9cb26ff6.js";const B={class:"fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50","scroll-region":""},C=a("div",{class:"absolute inset-0 bg-slate-500 dark:bg-slate-900 opacity-75"},null,-1),E=[C],S={__name:"Modal",props:{show:{type:Boolean,default:!1},maxWidth:{type:String,default:"2xl"},closeable:{type:Boolean,default:!0}},emits:["close"],setup(e,{emit:d}){const s=e;x(()=>s.show,()=>{s.show?document.body.style.overflow="hidden":document.body.style.overflow=null});const r=()=>{s.closeable&&d("close")},m=t=>{t.key==="Escape"&&s.show&&r()};w(()=>document.addEventListener("keydown",m)),y(()=>{document.removeEventListener("keydown",m),document.body.style.overflow=null});const u=f(()=>({sm:"sm:max-w-sm",md:"sm:max-w-md",lg:"sm:max-w-lg",xl:"sm:max-w-xl","2xl":"sm:max-w-2xl","3xl":"sm:max-w-3xl","4xl":"sm:max-w-4xl","5xl":"sm:max-w-5xl","6xl":"sm:max-w-6xl","7xl":"sm:max-w-7xl"})[s.maxWidth]);return(t,z)=>(v(),h(_,{to:"body"},[o(c,{"leave-active-class":"duration-200"},{default:l(()=>[n(a("div",B,[o(c,{"enter-active-class":"ease-out duration-300","enter-from-class":"opacity-0","enter-to-class":"opacity-100","leave-active-class":"ease-in duration-200","leave-from-class":"opacity-100","leave-to-class":"opacity-0"},{default:l(()=>[n(a("div",{class:"fixed inset-0 transform transition-all",onClick:r},E,512),[[i,e.show]])]),_:1}),o(c,{"enter-active-class":"ease-out duration-300","enter-from-class":"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95","enter-to-class":"opacity-100 translate-y-0 sm:scale-100","leave-active-class":"ease-in duration-200","leave-from-class":"opacity-100 translate-y-0 sm:scale-100","leave-to-class":"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"},{default:l(()=>[n(a("div",{class:p(["mb-6 bg-white dark:bg-slate-800 rounded overflow-hidden shadow transform transition-all sm:w-full sm:mx-auto",b(u)])},[e.show?k(t.$slots,"default",{key:0}):g("",!0)],2),[[i,e.show]])]),_:3})],512),[[i,e.show]])]),_:3})]))}};export{S as _};
2 |
--------------------------------------------------------------------------------
/public/build/assets/DeleteUserForm-a3ec2a2d.js:
--------------------------------------------------------------------------------
1 | import{r as p,v as g,o as b,c as v,w as s,e as a,t as o,a as u,b as l,u as r,C as h,n as k}from"./app-9cb26ff6.js";import{_ as y}from"./ActionSection-bb60ff24.js";import{_}from"./DangerButton-db69db22.js";import{_ as C}from"./DialogModal-9a2b4a3d.js";import{_ as V}from"./InputError-71f77be1.js";import{_ as $}from"./SecondaryButton-4d541c38.js";import{_ as U}from"./TextInput-f97bd710.js";import"./SectionTitle-1f89132a.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index-afa3307c.js";import"./Modal-d953ae84.js";const D={class:"max-w-xl text-sm text-slate-600 dark:text-slate-400"},B={class:"mt-5"},K={class:"mt-4"},A={__name:"DeleteUserForm",setup(N){const n=p(!1),c=p(null),e=g({password:""}),f=()=>{n.value=!0,setTimeout(()=>c.value.focus(),250)},d=()=>{e.delete(route("current-user.destroy"),{preserveScroll:!0,onSuccess:()=>i(),onError:()=>c.value.focus(),onFinish:()=>e.reset()})},i=()=>{n.value=!1,e.reset()};return(t,m)=>(b(),v(y,null,{title:s(()=>[a(o(t.lang().label.delete_account),1)]),description:s(()=>[a(o(t.lang().label.delete_account_description),1)]),content:s(()=>[u("div",D,o(t.lang().label.delete_account_content),1),u("div",B,[l(_,{onClick:f},{default:s(()=>[a(o(t.lang().button.delete_account),1)]),_:1})]),l(C,{show:n.value,onClose:i},{title:s(()=>[a(o(t.lang().label.delete_account),1)]),content:s(()=>[a(o(t.lang().label.delete_account_confirm)+" ",1),u("div",K,[l(U,{ref_key:"passwordInput",ref:c,modelValue:r(e).password,"onUpdate:modelValue":m[0]||(m[0]=w=>r(e).password=w),type:"password",class:"mt-1 block w-full",placeholder:"Password",autocomplete:"current-password",onKeyup:h(d,["enter"]),error:r(e).errors.password},null,8,["modelValue","onKeyup","error"]),l(V,{message:r(e).errors.password,class:"mt-2"},null,8,["message"])])]),footer:s(()=>[l($,{onClick:i},{default:s(()=>[a(o(t.lang().button.cancel),1)]),_:1}),l(_,{class:k(["ml-3",{"opacity-25":r(e).processing}]),disabled:r(e).processing,onClick:d},{default:s(()=>[a(o(t.lang().button.delete_account)+" "+o(r(e).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])]),_:1}))}};export{A as default};
2 |
--------------------------------------------------------------------------------
/public/build/assets/Edit-d7112c95.js:
--------------------------------------------------------------------------------
1 | import{r as w,v as $,B as k,m as C,o as f,d as S,j as V,c as y,w as l,b as o,u as a,p as _,e as c,t as n,a as v,n as B}from"./app-9cb26ff6.js";import{_ as j}from"./DialogModal-9a2b4a3d.js";import{_ as D}from"./InputError-71f77be1.js";import{_ as E}from"./InputLabel-ef1a5601.js";import{_ as N}from"./ActionButton-0ff23640.js";import{_ as M}from"./PrimaryButton-0fb1f193.js";import{_ as O}from"./SecondaryButton-4d541c38.js";import{_ as U}from"./TextInput-f97bd710.js";import{a as z}from"./index-afa3307c.js";import"./Modal-d953ae84.js";const F=["onSubmit"],I={class:"space-y-1"},R={__name:"Edit",props:{title:String,roles:Object,permission:Object},emits:["open"],setup(b,{emit:g}){var u;const r=b,t=w(!1),s=$({name:"",guard_name:"web"});k(()=>{var e;t&&(s.name=(e=r.permission)==null?void 0:e.name)});const p=()=>{var e;s.put(route("permission.update",(e=r.permission)==null?void 0:e.id),{preserveScroll:!0,onSuccess:()=>m(),onError:()=>null,onFinish:()=>null})},m=()=>{t.value=!1,s.errors={},s.reset()};return(u=r.roles)==null||u.map(e=>({label:e.name,value:e.name})),(e,i)=>{const h=C("tooltip");return f(),S("div",null,[V((f(),y(N,{onClick:i[0]||(i[0]=_(d=>(t.value=!0,g("open")),["prevent"]))},{default:l(()=>[o(a(z),{class:"w-4 h-auto"})]),_:1})),[[h,e.lang().label.edit]]),o(j,{show:t.value,onClose:m},{title:l(()=>[c(n(e.lang().label.edit)+" "+n(r.title),1)]),content:l(()=>[v("form",{class:"space-y-2",onSubmit:_(p,["prevent"])},[v("div",I,[o(E,{for:"name",value:e.lang().label.name},null,8,["value"]),o(U,{id:"name",modelValue:a(s).name,"onUpdate:modelValue":i[1]||(i[1]=d=>a(s).name=d),type:"text",class:"block w-full",autocomplete:"name",placeholder:e.lang().placeholder.permission_name,error:a(s).errors.name},null,8,["modelValue","placeholder","error"]),o(D,{message:a(s).errors.name},null,8,["message"])])],40,F)]),footer:l(()=>[o(O,{onClick:m},{default:l(()=>[c(n(e.lang().button.cancel),1)]),_:1}),o(M,{class:B(["ml-3",{"opacity-25":a(s).processing}]),disabled:a(s).processing,onClick:p},{default:l(()=>[c(n(e.lang().button.save)+" "+n(a(s).processing?"...":""),1)]),_:1},8,["class","disabled"])]),_:1},8,["show"])])}}};export{R as default};
2 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | public function definition(): array
26 | {
27 | return [
28 | 'name' => $this->faker->name(),
29 | 'email' => $this->faker->unique()->safeEmail(),
30 | 'email_verified_at' => now(),
31 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
32 | 'two_factor_secret' => null,
33 | 'two_factor_recovery_codes' => null,
34 | 'remember_token' => Str::random(10),
35 | 'profile_photo_path' => null,
36 | 'current_team_id' => null,
37 | ];
38 | }
39 |
40 | /**
41 | * Indicate that the model's email address should be unverified.
42 | */
43 | public function unverified(): static
44 | {
45 | return $this->state(function (array $attributes) {
46 | return [
47 | 'email_verified_at' => null,
48 | ];
49 | });
50 | }
51 |
52 | /**
53 | * Indicate that the user should have a personal team.
54 | */
55 | public function withPersonalTeam(): static
56 | {
57 | if (! Features::hasTeamFeatures()) {
58 | return $this->state([]);
59 | }
60 |
61 | return $this->has(
62 | Team::factory()
63 | ->state(function (array $attributes, User $user) {
64 | return ['name' => $user->name.'\'s Team', 'user_id' => $user->id, 'personal_team' => true];
65 | }),
66 | 'ownedTeams'
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/resources/js/Components/ConfirmationModal.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
34 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/public/build/assets/VerifyEmail-fb5fdae9.js:
--------------------------------------------------------------------------------
1 | import{v as _,z as g,o as n,d as f,b as o,u as t,X as h,w as i,a,t as s,g as b,n as v,e as r,x as m,p as x,F as k}from"./app-9cb26ff6.js";import{_ as y}from"./AuthenticationCard-4227316f.js";import{_ as w}from"./AuthenticationCardLogo-a2386df2.js";import{_ as S}from"./PrimaryButton-0fb1f193.js";import"./SwitchLocale-b9e142e8.js";import"./SwitchDarkMode-e6f628a6.js";import"./index-afa3307c.js";import"./ApplicationLogo-914092fa.js";import"./_plugin-vue_export-helper-c27b6911.js";const V={class:"flex flex-col mb-4"},N={class:"text-primary font-semibold text-xl"},B={class:"text-slate-400"},C={key:0,class:"mb-4 font-medium text-sm text-green-600 dark:text-green-400"},$=["onSubmit"],z={class:"mt-4 flex flex-col gap-4 items-center justify-between"},G={__name:"VerifyEmail",props:{status:String},setup(c){const u=c,l=_({}),d=()=>{l.post(route("verification.send"))},p=g(()=>u.status==="verification-link-sent");return(e,E)=>(n(),f(k,null,[o(t(h),{title:e.lang().label.email_verification},null,8,["title"]),o(y,null,{logo:i(()=>[o(w)]),default:i(()=>[a("div",V,[a("h2",N,s(e.lang().label.verify_email),1),a("small",B,s(e.lang().label.verify_email_caption),1)]),t(p)?(n(),f("div",C,s(e.lang().label.email_verification_link),1)):b("",!0),a("form",{onSubmit:x(d,["prevent"])},[a("div",z,[o(S,{class:v({"opacity-25":t(l).processing}),disabled:t(l).processing},{default:i(()=>[r(s(e.lang().button.resend_email_verification_link)+" "+s(t(l).processing?"...":""),1)]),_:1},8,["class","disabled"]),a("div",null,[o(t(m),{href:e.route("profile.show"),class:"underline text-sm text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary dark:focus:ring-offset-slate-800"},{default:i(()=>[r(s(e.lang().label.edit_profile),1)]),_:1},8,["href"]),o(t(m),{href:e.route("logout"),method:"post",as:"button",class:"underline text-sm text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary dark:focus:ring-offset-slate-800 ml-2"},{default:i(()=>[r(s(e.lang().label.logout),1)]),_:1},8,["href"])])])],40,$)]),_:1})],64))}};export{G as default};
2 |
--------------------------------------------------------------------------------
/resources/js/Pages/Auth/ForgotPassword.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |