Added admin panel
This commit is contained in:
		
							
								
								
									
										145
									
								
								Server/app/resources/admin/AdminController.jl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								Server/app/resources/admin/AdminController.jl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
module AdminController
 | 
			
		||||
 | 
			
		||||
using Genie, Genie.Renderer, Genie.Renderer.Html, Genie.Requests, GenieAuthentication, DataFrames, GenieAuthorisation
 | 
			
		||||
using JSON3
 | 
			
		||||
using SearchLight,SearchLightPostgreSQL, LibPQ, JSON3
 | 
			
		||||
using Server.DatabaseSupport, Server.TemplateEditor, Server.Users
 | 
			
		||||
import Server.DatabaseSupport: select_from_table, insert_into_table, delete_from_table, exist_in_table
 | 
			
		||||
 | 
			
		||||
controller = "admin"
 | 
			
		||||
dict_layouts = Dict(
 | 
			
		||||
    :admin_panel => generate_layout_html("main",controller,"admin-panel"),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
#---Page info-----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
const admin_panel_info = Dict(
 | 
			
		||||
    "en" => Dict(
 | 
			
		||||
        :title => "LibSoc - Admin panel",
 | 
			
		||||
        :description => ""
 | 
			
		||||
    ),
 | 
			
		||||
    "ru" => Dict(
 | 
			
		||||
        :title => "",
 | 
			
		||||
        :description => ""
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
function get_locale()
 | 
			
		||||
    data = payload()
 | 
			
		||||
    if :locale in keys(data)
 | 
			
		||||
        return data[:locale]
 | 
			
		||||
    else
 | 
			
		||||
        return "en"
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
#---Helpers-----------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function table_to_json(name,df)
 | 
			
		||||
    ar = []
 | 
			
		||||
    for df_row in eachrow(df)
 | 
			
		||||
        dict = Dict()
 | 
			
		||||
        for id in names(df_row)
 | 
			
		||||
            dict[id] = df_row[id]
 | 
			
		||||
        end
 | 
			
		||||
        push!(ar,dict)
 | 
			
		||||
    end
 | 
			
		||||
    open("public/assets/"*name*".json", "w") do io
 | 
			
		||||
        JSON3.write(io, ar)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function compile(name)
 | 
			
		||||
    df = select_from_table([name => ["*"]])
 | 
			
		||||
    table_to_json(name,df)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function move_requests(name)
 | 
			
		||||
    df_requests = select_from_table(["$(name)_requests" => ["*"]], where_data=["verified" => true, "added" => false])
 | 
			
		||||
    df = select_from_table([name => ["*"]])
 | 
			
		||||
    latitudes = df.latitude
 | 
			
		||||
    longitudes = df.longitude
 | 
			
		||||
    for df_row in eachrow(df_requests)
 | 
			
		||||
        ind_id_given = ismissing(df_row.id_given) ? nothing : findfirst(df_row.id_given.==df.id)
 | 
			
		||||
        if (!isnothing(ind_id_given))
 | 
			
		||||
            id = df[ind_id_given,:id]
 | 
			
		||||
            row_found = df[ind_id_given,Not(:id)]
 | 
			
		||||
            dict = Dict(zip(names(row_found),values(row_found)))
 | 
			
		||||
            dict["members"] += 1
 | 
			
		||||
            update_table(name,dict, where_data=["id" => id])
 | 
			
		||||
        else
 | 
			
		||||
            id = df_row.id
 | 
			
		||||
            dict_update = Dict("added" => true)
 | 
			
		||||
            update_table("$(name)_requests",dict_update, where_data=["id" => id])
 | 
			
		||||
 | 
			
		||||
            df_row_to_add = df_row[Not(:id_given)]
 | 
			
		||||
            df_row_to_add = df_row_to_add[Not(:verified)]
 | 
			
		||||
            df_row_to_add = df_row_to_add[Not(:added)]
 | 
			
		||||
            df_row_to_add = df_row_to_add[Not(:id)]
 | 
			
		||||
            dict = Dict(zip(names(df_row_to_add),values(df_row_to_add)))
 | 
			
		||||
            dict["members"] = 1
 | 
			
		||||
            insert_into_table(name,dict)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
#---Functions---------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
current_user() = findone(Users.User, id = get_authentication())
 | 
			
		||||
 | 
			
		||||
function admin_panel()
 | 
			
		||||
    @info has_permission(current_user(), "verification")
 | 
			
		||||
    @info current_user()
 | 
			
		||||
    if has_permission(current_user(), "verification")
 | 
			
		||||
        locale = get_locale()
 | 
			
		||||
        html(:admin,:admin_panel, layout = dict_layouts[:admin_panel], context = @__MODULE__,
 | 
			
		||||
            title = admin_panel_info[locale][:title],
 | 
			
		||||
            description = admin_panel_info[locale][:description]
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function verify()
 | 
			
		||||
    if has_permission(current_user(), "verification")
 | 
			
		||||
        data = copy(jsonpayload())
 | 
			
		||||
        user_id = data["user_id"]
 | 
			
		||||
        update_table("users",Dict("verified" => true), where_data=["id" => user_id])
 | 
			
		||||
        return nothing
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function get_unverified_users()
 | 
			
		||||
    if has_permission(current_user(), "verification")
 | 
			
		||||
        users = select_from_table("users" => ["id","email"], where_data = ["verified" => false])
 | 
			
		||||
        data = []
 | 
			
		||||
        if size(users,1)!=0
 | 
			
		||||
            for x in eachrow(users)
 | 
			
		||||
                dict = Dict("user_id" => x["id"],"email" => x["email"])
 | 
			
		||||
                push!(data, dict)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        return JSON3.write(data)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function add_verified_groups()
 | 
			
		||||
    if has_permission(current_user(), "admin")
 | 
			
		||||
        groups_create_requests_verified = select_from_table("groups_requests" => ["*"], where_data = ["group_id" => nothing, "status" => 1])
 | 
			
		||||
        if size(groups_create_requests_verified,1)!=0
 | 
			
		||||
            data = Dict(zip(names(groups_create_requests_verified),groups_create_requests_verified[end,:]))
 | 
			
		||||
            user_id = data["user_id"]
 | 
			
		||||
            delete!(data,"group_id")
 | 
			
		||||
            delete!(data,"user_id")
 | 
			
		||||
            delete!(data,"id")
 | 
			
		||||
            delete!(data,"status")
 | 
			
		||||
            group_id = insert_into_table("groups",data, "RETURNING id")[1,1]
 | 
			
		||||
            dict_users_groups = Dict("user_id" => user_id, "group_id" => group_id)
 | 
			
		||||
            insert_into_table("users_groups",dict_users_groups)
 | 
			
		||||
            delete_from_table("groups_requests",["user_id" => user_id])
 | 
			
		||||
        end
 | 
			
		||||
        compile("groups")
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										1
									
								
								Server/app/resources/admin/views/admin_panel.jl.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Server/app/resources/admin/views/admin_panel.jl.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<admin-panel></admin-panel>
 | 
			
		||||
@@ -245,23 +245,6 @@ function reject_request()
 | 
			
		||||
    return nothing
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function add_verified_groups()
 | 
			
		||||
    groups_create_requests_verified = select_from_table("groups_requests" => ["*"], where_data = ["group_id" => nothing, "status" => 1])
 | 
			
		||||
    if size(groups_create_requests_verified,1)!=0
 | 
			
		||||
        data = Dict(zip(names(groups_create_requests_verified),groups_create_requests_verified[end,:]))
 | 
			
		||||
        user_id = data["user_id"]
 | 
			
		||||
        delete!(data,"group_id")
 | 
			
		||||
        delete!(data,"user_id")
 | 
			
		||||
        delete!(data,"id")
 | 
			
		||||
        delete!(data,"status")
 | 
			
		||||
        group_id = insert_into_table("groups",data, "RETURNING id")[1,1]
 | 
			
		||||
        dict_users_groups = Dict("user_id" => user_id, "group_id" => group_id)
 | 
			
		||||
        insert_into_table("users_groups",dict_users_groups)
 | 
			
		||||
        delete_from_table("groups_requests",["user_id" => user_id])
 | 
			
		||||
    end
 | 
			
		||||
    compile("groups")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function changeMemberCount()
 | 
			
		||||
    user_id = get_authentication()
 | 
			
		||||
    groups_ids = select_from_table("users_groups" => ["group_id"], where_data = ["user_id" => user_id])[:,1]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										140
									
								
								Server/app/svelte/src/admin-panel.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								Server/app/svelte/src/admin-panel.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
<svelte:options tag="admin-panel" />
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
    // Import statements
 | 
			
		||||
    import { onMount, getContext } from 'svelte'
 | 
			
		||||
    import { writable } from 'svelte/store'
 | 
			
		||||
    import { getData, sendData } from "/js/libraries/serverTools.js"
 | 
			
		||||
 | 
			
		||||
    //Import components
 | 
			
		||||
    import "/js/components/select-component.js"
 | 
			
		||||
    import "/js/components/switch-component.js" 
 | 
			
		||||
    import "/js/components/pane-aligner.js" 
 | 
			
		||||
 | 
			
		||||
    //Export statements
 | 
			
		||||
 | 
			
		||||
    // Main code
 | 
			
		||||
    let section
 | 
			
		||||
    let requests_verification = []
 | 
			
		||||
    let loaded = writable(0)
 | 
			
		||||
    let keyRequests = 0
 | 
			
		||||
    let numLoaded = 1
 | 
			
		||||
    let mainPane
 | 
			
		||||
 | 
			
		||||
    let context = getContext("profile-component")
 | 
			
		||||
 | 
			
		||||
    function requests_callback(response) {
 | 
			
		||||
        let parsed = JSON.parse(response)
 | 
			
		||||
        requests_verification.push(...parsed)
 | 
			
		||||
        loaded.update((val) => {
 | 
			
		||||
            return val + 1
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    getData("/xx/get-unverified-users",requests_callback)
 | 
			
		||||
 | 
			
		||||
    function approveRequest(ind,user_id) {
 | 
			
		||||
        sendData("/xx/verify",{user_id: user_id})
 | 
			
		||||
        requests_verification.splice(ind,1)
 | 
			
		||||
        keyRequests = keyRequests + 1
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addVerified() {
 | 
			
		||||
        getData("/xx/add-verified-groups",() => "")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onMount(() => {
 | 
			
		||||
	})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#key $loaded}
 | 
			
		||||
    {#if $loaded==numLoaded}
 | 
			
		||||
        <pane-aligner>
 | 
			
		||||
            <div bind:this={mainPane} slot="main">
 | 
			
		||||
                <h3>User verification</h3>
 | 
			
		||||
                <section bind:this={section} class="entries-section">
 | 
			
		||||
                    {#key keyRequests}
 | 
			
		||||
                        {#each requests_verification as req,ind}
 | 
			
		||||
                            <div>
 | 
			
		||||
                                <div class="change-field-line">
 | 
			
		||||
                                    <span>{req.email}</span>
 | 
			
		||||
                                    <div class="request-button-wrapper">
 | 
			
		||||
                                        <button on:click={() => approveRequest(ind,req.user_id)} class="default-button approve-button">Approve</button>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>         
 | 
			
		||||
                        {/each}
 | 
			
		||||
                    {/key}
 | 
			
		||||
                    <button on:click={addVerified} id="add-verified-button" class="default-button">Add verified pins</button>
 | 
			
		||||
                </section>
 | 
			
		||||
            </div>
 | 
			
		||||
        </pane-aligner>
 | 
			
		||||
    {/if}
 | 
			
		||||
{/key}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
    @import '/css/common.css';
 | 
			
		||||
 | 
			
		||||
    .request-button-wrapper {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        gap: 1rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .default-button {
 | 
			
		||||
        height: 2.7rem;
 | 
			
		||||
        padding: 0rem 1rem;
 | 
			
		||||
        font-family: var(--sans-serif,sans-serif);
 | 
			
		||||
        font-size: 1.15rem;
 | 
			
		||||
        color: white;
 | 
			
		||||
        background-color: var(--red);
 | 
			
		||||
        border-color: var(--red);
 | 
			
		||||
        border-radius: 0.5rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .approve-button {
 | 
			
		||||
        margin-top: -0.45rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #add-verified-button {
 | 
			
		||||
        margin-top: 1rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .entries-section {
 | 
			
		||||
        margin-bottom: 1rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .entries-section >div {
 | 
			
		||||
        height: 3.5rem;
 | 
			
		||||
        padding-bottom: 0.75rem;
 | 
			
		||||
        padding-top: 0.75rem;
 | 
			
		||||
        border-bottom: 0.14rem solid;
 | 
			
		||||
        border-color: #cdcdcd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* add padding to every line to center the diving line*/
 | 
			
		||||
    .entries-section >div:last-child {
 | 
			
		||||
        padding-bottom: 0.75rem;
 | 
			
		||||
        padding-top: 0.75rem;
 | 
			
		||||
        border-bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
     /*---Change field-------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
    .change-field-line {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    /*---General section-----------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
    h3 {
 | 
			
		||||
        margin-bottom: 0.5rem;
 | 
			
		||||
    }
 | 
			
		||||
    span {
 | 
			
		||||
        font-family: var(--sans-serif,sans-serif);
 | 
			
		||||
        font-size: 1.15rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -25,6 +25,9 @@ SearchLight.Configuration.load() |> SearchLight.connect
 | 
			
		||||
#SearchLight.Migration.all_up!!(context=Server)
 | 
			
		||||
#SearchLight.Migration.status()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#---Create tables----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
p = "db/migrations/"
 | 
			
		||||
files = readdir(p)
 | 
			
		||||
files = files[map(x -> x[end-1:end].=="jl", files)]
 | 
			
		||||
@@ -39,3 +42,23 @@ for f in files
 | 
			
		||||
    catch
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#---Initialize Genie Authorization----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
using GenieAuthorisation
 | 
			
		||||
using GenieAuthorisation: findone_or_create, save!, findone
 | 
			
		||||
 | 
			
		||||
# Create roles
 | 
			
		||||
for r in ["admin"]
 | 
			
		||||
    findone_or_create(Role, name = r) |> save!
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Create permissions
 | 
			
		||||
for p in ["verification"]
 | 
			
		||||
    findone_or_create(Permission, name = p) |> save!
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
assign_permission(findone(Role, name = "admin"), findone(Permission, name = "verification"))
 | 
			
		||||
 | 
			
		||||
# assign_role(findone(User, email = "user@user"), findone(Role, name = "admin"))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								Server/public/js/components/admin-panel.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Server/public/js/components/admin-panel.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
import{S as t,i as e,a as n,b as o,s,e as r,n as i,d as a,c,g as d,o as l,f as m,h as p,j as u,k as f,l as h,m as g,p as b,t as v}from"./index-0d9f0c09.js";import{w as x}from"./index-1c123138.js";import{getData as j,sendData as w}from"../../../../../../../../../js/libraries/serverTools.js";import"../../../../../../../../../js/components/select-component.js";import"../../../../../../../../../js/components/switch-component.js";import"../../../../../../../../../js/components/pane-aligner.js";function y(t,e,n){const o=t.slice();return o[13]=e[n],o[15]=n,o}function k(t){let e,n,r,i,c,d,l,m,b,v=t[1],x=C(t);return{c(){e=p("pane-aligner"),n=p("div"),r=p("h3"),r.textContent="User verification",i=u(),c=p("section"),x.c(),d=u(),l=p("button"),l.textContent="Add verified pins",f(l,"id","add-verified-button"),f(l,"class","default-button"),f(c,"class","entries-section"),f(n,"slot","main")},m(s,a){o(s,e,a),h(e,n),h(n,r),h(n,i),h(n,c),x.m(c,null),h(c,d),h(c,l),t[9](c),t[10](n),m||(b=g(l,"click",t[7]),m=!0)},p(t,e){2&e&&s(v,v=t[1])?(x.d(1),x=C(t),x.c(),x.m(c,d)):x.p(t,e)},d(n){n&&a(e),x.d(n),t[9](null),t[10](null),m=!1,b()}}}function N(t){let e,n,s,r,i,c,d,l,m,b,x=t[13].email+"";function j(){return t[8](t[15],t[13])}return{c(){e=p("div"),n=p("div"),s=p("span"),r=v(x),i=u(),c=p("div"),d=p("button"),d.textContent="Approve",l=u(),f(d,"class","default-button approve-button"),f(c,"class","request-button-wrapper"),f(n,"class","change-field-line")},m(t,a){o(t,e,a),h(e,n),h(n,s),h(s,r),h(n,i),h(n,c),h(c,d),h(e,l),m||(b=g(d,"click",j),m=!0)},p(e,n){t=e},d(t){t&&a(e),m=!1,b()}}}function C(t){let e,n=t[4],s=[];for(let e=0;e<n.length;e+=1)s[e]=N(y(t,n,e));return{c(){for(let t=0;t<s.length;t+=1)s[t].c();e=r()},m(t,n){for(let e=0;e<s.length;e+=1)s[e].m(t,n);o(t,e,n)},p(t,o){if(80&o){let r;for(n=t[4],r=0;r<n.length;r+=1){const i=y(t,n,r);s[r]?s[r].p(i,o):(s[r]=N(i),s[r].c(),s[r].m(e.parentNode,e))}for(;r<s.length;r+=1)s[r].d(1);s.length=n.length}},d(t){b(s,t),t&&a(e)}}}function q(t){let e,n=t[3]==A&&k(t);return{c(){n&&n.c(),e=r()},m(t,s){n&&n.m(t,s),o(t,e,s)},p(t,o){t[3]==A?n?n.p(t,o):(n=k(t),n.c(),n.m(e.parentNode,e)):n&&(n.d(1),n=null)},d(t){n&&n.d(t),t&&a(e)}}}function z(t){let e,n=t[3],c=q(t);return{c(){c.c(),e=r(),this.c=i},m(t,n){c.m(t,n),o(t,e,n)},p(t,[o]){8&o&&s(n,n=t[3])?(c.d(1),c=q(t),c.c(),c.m(e.parentNode,e)):c.p(t,o)},i:i,o:i,d(t){t&&a(e),c.d(t)}}}let A=1;function E(t,e,n){let o,s,r=[],i=x(0);c(t,i,(t=>n(3,o=t)));let a,p=0;function u(t,e){w("/xx/verify",{user_id:e}),r.splice(t,1),n(1,p+=1)}d("profile-component"),j("/xx/get-unverified-users",(function(t){let e=JSON.parse(t);r.push(...e),i.update((t=>t+1))})),l((()=>{}));return[s,p,a,o,r,i,u,function(){j("/xx/add-verified-groups",(()=>""))},(t,e)=>u(t,e.user_id),function(t){m[t?"unshift":"push"]((()=>{s=t,n(0,s)}))},function(t){m[t?"unshift":"push"]((()=>{a=t,n(2,a)}))}]}class R extends t{constructor(t){super(),this.shadowRoot.innerHTML="<style>@import '/css/common.css';.request-button-wrapper{display:flex;gap:1rem}.default-button{height:2.7rem;padding:0rem 1rem;font-family:var(--sans-serif,sans-serif);font-size:1.15rem;color:white;background-color:var(--red);border-color:var(--red);border-radius:0.5rem}.approve-button{margin-top:-0.45rem}#add-verified-button{margin-top:1rem}.entries-section{margin-bottom:1rem}.entries-section>div{height:3.5rem;padding-bottom:0.75rem;padding-top:0.75rem;border-bottom:0.14rem solid;border-color:#cdcdcd}.entries-section>div:last-child{padding-bottom:0.75rem;padding-top:0.75rem;border-bottom:0}.change-field-line{display:flex;justify-content:space-between}h3{margin-bottom:0.5rem}span{font-family:var(--sans-serif,sans-serif);font-size:1.15rem}</style>",e(this,{target:this.shadowRoot,props:n(this.attributes),customElement:!0},E,z,s,{},null),t&&t.target&&o(t.target,this,t.anchor)}}customElements.define("admin-panel",R);export{R as default};
 | 
			
		||||
							
								
								
									
										527
									
								
								Server/public/js/components/index-2620635a.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										527
									
								
								Server/public/js/components/index-2620635a.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,527 @@
 | 
			
		||||
 | 
			
		||||
(function(l, r) { if (!l || l.getElementById('livereloadscript')) return; r = l.createElement('script'); r.async = 1; r.src = '//' + (self.location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1'; r.id = 'livereloadscript'; l.getElementsByTagName('head')[0].appendChild(r) })(self.document);
 | 
			
		||||
function noop() { }
 | 
			
		||||
function add_location(element, file, line, column, char) {
 | 
			
		||||
    element.__svelte_meta = {
 | 
			
		||||
        loc: { file, line, column, char }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
function run(fn) {
 | 
			
		||||
    return fn();
 | 
			
		||||
}
 | 
			
		||||
function blank_object() {
 | 
			
		||||
    return Object.create(null);
 | 
			
		||||
}
 | 
			
		||||
function run_all(fns) {
 | 
			
		||||
    fns.forEach(run);
 | 
			
		||||
}
 | 
			
		||||
function is_function(thing) {
 | 
			
		||||
    return typeof thing === 'function';
 | 
			
		||||
}
 | 
			
		||||
function safe_not_equal(a, b) {
 | 
			
		||||
    return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
 | 
			
		||||
}
 | 
			
		||||
let src_url_equal_anchor;
 | 
			
		||||
function src_url_equal(element_src, url) {
 | 
			
		||||
    if (!src_url_equal_anchor) {
 | 
			
		||||
        src_url_equal_anchor = document.createElement('a');
 | 
			
		||||
    }
 | 
			
		||||
    src_url_equal_anchor.href = url;
 | 
			
		||||
    return element_src === src_url_equal_anchor.href;
 | 
			
		||||
}
 | 
			
		||||
function is_empty(obj) {
 | 
			
		||||
    return Object.keys(obj).length === 0;
 | 
			
		||||
}
 | 
			
		||||
function validate_store(store, name) {
 | 
			
		||||
    if (store != null && typeof store.subscribe !== 'function') {
 | 
			
		||||
        throw new Error(`'${name}' is not a store with a 'subscribe' method`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function subscribe(store, ...callbacks) {
 | 
			
		||||
    if (store == null) {
 | 
			
		||||
        return noop;
 | 
			
		||||
    }
 | 
			
		||||
    const unsub = store.subscribe(...callbacks);
 | 
			
		||||
    return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
 | 
			
		||||
}
 | 
			
		||||
function component_subscribe(component, store, callback) {
 | 
			
		||||
    component.$$.on_destroy.push(subscribe(store, callback));
 | 
			
		||||
}
 | 
			
		||||
function append(target, node) {
 | 
			
		||||
    target.appendChild(node);
 | 
			
		||||
}
 | 
			
		||||
function insert(target, node, anchor) {
 | 
			
		||||
    target.insertBefore(node, anchor || null);
 | 
			
		||||
}
 | 
			
		||||
function detach(node) {
 | 
			
		||||
    node.parentNode.removeChild(node);
 | 
			
		||||
}
 | 
			
		||||
function destroy_each(iterations, detaching) {
 | 
			
		||||
    for (let i = 0; i < iterations.length; i += 1) {
 | 
			
		||||
        if (iterations[i])
 | 
			
		||||
            iterations[i].d(detaching);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function element(name) {
 | 
			
		||||
    return document.createElement(name);
 | 
			
		||||
}
 | 
			
		||||
function svg_element(name) {
 | 
			
		||||
    return document.createElementNS('http://www.w3.org/2000/svg', name);
 | 
			
		||||
}
 | 
			
		||||
function text(data) {
 | 
			
		||||
    return document.createTextNode(data);
 | 
			
		||||
}
 | 
			
		||||
function space() {
 | 
			
		||||
    return text(' ');
 | 
			
		||||
}
 | 
			
		||||
function empty() {
 | 
			
		||||
    return text('');
 | 
			
		||||
}
 | 
			
		||||
function listen(node, event, handler, options) {
 | 
			
		||||
    node.addEventListener(event, handler, options);
 | 
			
		||||
    return () => node.removeEventListener(event, handler, options);
 | 
			
		||||
}
 | 
			
		||||
function attr(node, attribute, value) {
 | 
			
		||||
    if (value == null)
 | 
			
		||||
        node.removeAttribute(attribute);
 | 
			
		||||
    else if (node.getAttribute(attribute) !== value)
 | 
			
		||||
        node.setAttribute(attribute, value);
 | 
			
		||||
}
 | 
			
		||||
function set_custom_element_data(node, prop, value) {
 | 
			
		||||
    if (prop in node) {
 | 
			
		||||
        node[prop] = typeof node[prop] === 'boolean' && value === '' ? true : value;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        attr(node, prop, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function to_number(value) {
 | 
			
		||||
    return value === '' ? null : +value;
 | 
			
		||||
}
 | 
			
		||||
function children(element) {
 | 
			
		||||
    return Array.from(element.childNodes);
 | 
			
		||||
}
 | 
			
		||||
function set_input_value(input, value) {
 | 
			
		||||
    input.value = value == null ? '' : value;
 | 
			
		||||
}
 | 
			
		||||
function set_style(node, key, value, important) {
 | 
			
		||||
    if (value === null) {
 | 
			
		||||
        node.style.removeProperty(key);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        node.style.setProperty(key, value, important ? 'important' : '');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {
 | 
			
		||||
    const e = document.createEvent('CustomEvent');
 | 
			
		||||
    e.initCustomEvent(type, bubbles, cancelable, detail);
 | 
			
		||||
    return e;
 | 
			
		||||
}
 | 
			
		||||
class HtmlTag {
 | 
			
		||||
    constructor(is_svg = false) {
 | 
			
		||||
        this.is_svg = false;
 | 
			
		||||
        this.is_svg = is_svg;
 | 
			
		||||
        this.e = this.n = null;
 | 
			
		||||
    }
 | 
			
		||||
    c(html) {
 | 
			
		||||
        this.h(html);
 | 
			
		||||
    }
 | 
			
		||||
    m(html, target, anchor = null) {
 | 
			
		||||
        if (!this.e) {
 | 
			
		||||
            if (this.is_svg)
 | 
			
		||||
                this.e = svg_element(target.nodeName);
 | 
			
		||||
            else
 | 
			
		||||
                this.e = element(target.nodeName);
 | 
			
		||||
            this.t = target;
 | 
			
		||||
            this.c(html);
 | 
			
		||||
        }
 | 
			
		||||
        this.i(anchor);
 | 
			
		||||
    }
 | 
			
		||||
    h(html) {
 | 
			
		||||
        this.e.innerHTML = html;
 | 
			
		||||
        this.n = Array.from(this.e.childNodes);
 | 
			
		||||
    }
 | 
			
		||||
    i(anchor) {
 | 
			
		||||
        for (let i = 0; i < this.n.length; i += 1) {
 | 
			
		||||
            insert(this.t, this.n[i], anchor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    p(html) {
 | 
			
		||||
        this.d();
 | 
			
		||||
        this.h(html);
 | 
			
		||||
        this.i(this.a);
 | 
			
		||||
    }
 | 
			
		||||
    d() {
 | 
			
		||||
        this.n.forEach(detach);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function attribute_to_object(attributes) {
 | 
			
		||||
    const result = {};
 | 
			
		||||
    for (const attribute of attributes) {
 | 
			
		||||
        result[attribute.name] = attribute.value;
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let current_component;
 | 
			
		||||
function set_current_component(component) {
 | 
			
		||||
    current_component = component;
 | 
			
		||||
}
 | 
			
		||||
function get_current_component() {
 | 
			
		||||
    if (!current_component)
 | 
			
		||||
        throw new Error('Function called outside component initialization');
 | 
			
		||||
    return current_component;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
 | 
			
		||||
 * It must be called during the component's initialisation (but doesn't need to live *inside* the component;
 | 
			
		||||
 * it can be called from an external module).
 | 
			
		||||
 *
 | 
			
		||||
 * `onMount` does not run inside a [server-side component](/docs#run-time-server-side-component-api).
 | 
			
		||||
 *
 | 
			
		||||
 * https://svelte.dev/docs#run-time-svelte-onmount
 | 
			
		||||
 */
 | 
			
		||||
function onMount(fn) {
 | 
			
		||||
    get_current_component().$$.on_mount.push(fn);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * Schedules a callback to run immediately after the component has been updated.
 | 
			
		||||
 *
 | 
			
		||||
 * The first time the callback runs will be after the initial `onMount`
 | 
			
		||||
 */
 | 
			
		||||
function afterUpdate(fn) {
 | 
			
		||||
    get_current_component().$$.after_update.push(fn);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * Associates an arbitrary `context` object with the current component and the specified `key`
 | 
			
		||||
 * and returns that object. The context is then available to children of the component
 | 
			
		||||
 * (including slotted content) with `getContext`.
 | 
			
		||||
 *
 | 
			
		||||
 * Like lifecycle functions, this must be called during component initialisation.
 | 
			
		||||
 *
 | 
			
		||||
 * https://svelte.dev/docs#run-time-svelte-setcontext
 | 
			
		||||
 */
 | 
			
		||||
function setContext(key, context) {
 | 
			
		||||
    get_current_component().$$.context.set(key, context);
 | 
			
		||||
    return context;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * Retrieves the context that belongs to the closest parent component with the specified `key`.
 | 
			
		||||
 * Must be called during component initialisation.
 | 
			
		||||
 *
 | 
			
		||||
 * https://svelte.dev/docs#run-time-svelte-getcontext
 | 
			
		||||
 */
 | 
			
		||||
function getContext(key) {
 | 
			
		||||
    return get_current_component().$$.context.get(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const dirty_components = [];
 | 
			
		||||
const binding_callbacks = [];
 | 
			
		||||
const render_callbacks = [];
 | 
			
		||||
const flush_callbacks = [];
 | 
			
		||||
const resolved_promise = Promise.resolve();
 | 
			
		||||
let update_scheduled = false;
 | 
			
		||||
function schedule_update() {
 | 
			
		||||
    if (!update_scheduled) {
 | 
			
		||||
        update_scheduled = true;
 | 
			
		||||
        resolved_promise.then(flush);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function add_render_callback(fn) {
 | 
			
		||||
    render_callbacks.push(fn);
 | 
			
		||||
}
 | 
			
		||||
// flush() calls callbacks in this order:
 | 
			
		||||
// 1. All beforeUpdate callbacks, in order: parents before children
 | 
			
		||||
// 2. All bind:this callbacks, in reverse order: children before parents.
 | 
			
		||||
// 3. All afterUpdate callbacks, in order: parents before children. EXCEPT
 | 
			
		||||
//    for afterUpdates called during the initial onMount, which are called in
 | 
			
		||||
//    reverse order: children before parents.
 | 
			
		||||
// Since callbacks might update component values, which could trigger another
 | 
			
		||||
// call to flush(), the following steps guard against this:
 | 
			
		||||
// 1. During beforeUpdate, any updated components will be added to the
 | 
			
		||||
//    dirty_components array and will cause a reentrant call to flush(). Because
 | 
			
		||||
//    the flush index is kept outside the function, the reentrant call will pick
 | 
			
		||||
//    up where the earlier call left off and go through all dirty components. The
 | 
			
		||||
//    current_component value is saved and restored so that the reentrant call will
 | 
			
		||||
//    not interfere with the "parent" flush() call.
 | 
			
		||||
// 2. bind:this callbacks cannot trigger new flush() calls.
 | 
			
		||||
// 3. During afterUpdate, any updated components will NOT have their afterUpdate
 | 
			
		||||
//    callback called a second time; the seen_callbacks set, outside the flush()
 | 
			
		||||
//    function, guarantees this behavior.
 | 
			
		||||
const seen_callbacks = new Set();
 | 
			
		||||
let flushidx = 0; // Do *not* move this inside the flush() function
 | 
			
		||||
function flush() {
 | 
			
		||||
    const saved_component = current_component;
 | 
			
		||||
    do {
 | 
			
		||||
        // first, call beforeUpdate functions
 | 
			
		||||
        // and update components
 | 
			
		||||
        while (flushidx < dirty_components.length) {
 | 
			
		||||
            const component = dirty_components[flushidx];
 | 
			
		||||
            flushidx++;
 | 
			
		||||
            set_current_component(component);
 | 
			
		||||
            update(component.$$);
 | 
			
		||||
        }
 | 
			
		||||
        set_current_component(null);
 | 
			
		||||
        dirty_components.length = 0;
 | 
			
		||||
        flushidx = 0;
 | 
			
		||||
        while (binding_callbacks.length)
 | 
			
		||||
            binding_callbacks.pop()();
 | 
			
		||||
        // then, once components are updated, call
 | 
			
		||||
        // afterUpdate functions. This may cause
 | 
			
		||||
        // subsequent updates...
 | 
			
		||||
        for (let i = 0; i < render_callbacks.length; i += 1) {
 | 
			
		||||
            const callback = render_callbacks[i];
 | 
			
		||||
            if (!seen_callbacks.has(callback)) {
 | 
			
		||||
                // ...so guard against infinite loops
 | 
			
		||||
                seen_callbacks.add(callback);
 | 
			
		||||
                callback();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        render_callbacks.length = 0;
 | 
			
		||||
    } while (dirty_components.length);
 | 
			
		||||
    while (flush_callbacks.length) {
 | 
			
		||||
        flush_callbacks.pop()();
 | 
			
		||||
    }
 | 
			
		||||
    update_scheduled = false;
 | 
			
		||||
    seen_callbacks.clear();
 | 
			
		||||
    set_current_component(saved_component);
 | 
			
		||||
}
 | 
			
		||||
function update($$) {
 | 
			
		||||
    if ($$.fragment !== null) {
 | 
			
		||||
        $$.update();
 | 
			
		||||
        run_all($$.before_update);
 | 
			
		||||
        const dirty = $$.dirty;
 | 
			
		||||
        $$.dirty = [-1];
 | 
			
		||||
        $$.fragment && $$.fragment.p($$.ctx, dirty);
 | 
			
		||||
        $$.after_update.forEach(add_render_callback);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
const outroing = new Set();
 | 
			
		||||
function transition_in(block, local) {
 | 
			
		||||
    if (block && block.i) {
 | 
			
		||||
        outroing.delete(block);
 | 
			
		||||
        block.i(local);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const globals = (typeof window !== 'undefined'
 | 
			
		||||
    ? window
 | 
			
		||||
    : typeof globalThis !== 'undefined'
 | 
			
		||||
        ? globalThis
 | 
			
		||||
        : global);
 | 
			
		||||
function mount_component(component, target, anchor, customElement) {
 | 
			
		||||
    const { fragment, after_update } = component.$$;
 | 
			
		||||
    fragment && fragment.m(target, anchor);
 | 
			
		||||
    if (!customElement) {
 | 
			
		||||
        // onMount happens before the initial afterUpdate
 | 
			
		||||
        add_render_callback(() => {
 | 
			
		||||
            const new_on_destroy = component.$$.on_mount.map(run).filter(is_function);
 | 
			
		||||
            // if the component was destroyed immediately
 | 
			
		||||
            // it will update the `$$.on_destroy` reference to `null`.
 | 
			
		||||
            // the destructured on_destroy may still reference to the old array
 | 
			
		||||
            if (component.$$.on_destroy) {
 | 
			
		||||
                component.$$.on_destroy.push(...new_on_destroy);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // Edge case - component was destroyed immediately,
 | 
			
		||||
                // most likely as a result of a binding initialising
 | 
			
		||||
                run_all(new_on_destroy);
 | 
			
		||||
            }
 | 
			
		||||
            component.$$.on_mount = [];
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    after_update.forEach(add_render_callback);
 | 
			
		||||
}
 | 
			
		||||
function destroy_component(component, detaching) {
 | 
			
		||||
    const $$ = component.$$;
 | 
			
		||||
    if ($$.fragment !== null) {
 | 
			
		||||
        run_all($$.on_destroy);
 | 
			
		||||
        $$.fragment && $$.fragment.d(detaching);
 | 
			
		||||
        // TODO null out other refs, including component.$$ (but need to
 | 
			
		||||
        // preserve final state?)
 | 
			
		||||
        $$.on_destroy = $$.fragment = null;
 | 
			
		||||
        $$.ctx = [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function make_dirty(component, i) {
 | 
			
		||||
    if (component.$$.dirty[0] === -1) {
 | 
			
		||||
        dirty_components.push(component);
 | 
			
		||||
        schedule_update();
 | 
			
		||||
        component.$$.dirty.fill(0);
 | 
			
		||||
    }
 | 
			
		||||
    component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
 | 
			
		||||
}
 | 
			
		||||
function init(component, options, instance, create_fragment, not_equal, props, append_styles, dirty = [-1]) {
 | 
			
		||||
    const parent_component = current_component;
 | 
			
		||||
    set_current_component(component);
 | 
			
		||||
    const $$ = component.$$ = {
 | 
			
		||||
        fragment: null,
 | 
			
		||||
        ctx: [],
 | 
			
		||||
        // state
 | 
			
		||||
        props,
 | 
			
		||||
        update: noop,
 | 
			
		||||
        not_equal,
 | 
			
		||||
        bound: blank_object(),
 | 
			
		||||
        // lifecycle
 | 
			
		||||
        on_mount: [],
 | 
			
		||||
        on_destroy: [],
 | 
			
		||||
        on_disconnect: [],
 | 
			
		||||
        before_update: [],
 | 
			
		||||
        after_update: [],
 | 
			
		||||
        context: new Map(options.context || (parent_component ? parent_component.$$.context : [])),
 | 
			
		||||
        // everything else
 | 
			
		||||
        callbacks: blank_object(),
 | 
			
		||||
        dirty,
 | 
			
		||||
        skip_bound: false,
 | 
			
		||||
        root: options.target || parent_component.$$.root
 | 
			
		||||
    };
 | 
			
		||||
    append_styles && append_styles($$.root);
 | 
			
		||||
    let ready = false;
 | 
			
		||||
    $$.ctx = instance
 | 
			
		||||
        ? instance(component, options.props || {}, (i, ret, ...rest) => {
 | 
			
		||||
            const value = rest.length ? rest[0] : ret;
 | 
			
		||||
            if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
 | 
			
		||||
                if (!$$.skip_bound && $$.bound[i])
 | 
			
		||||
                    $$.bound[i](value);
 | 
			
		||||
                if (ready)
 | 
			
		||||
                    make_dirty(component, i);
 | 
			
		||||
            }
 | 
			
		||||
            return ret;
 | 
			
		||||
        })
 | 
			
		||||
        : [];
 | 
			
		||||
    $$.update();
 | 
			
		||||
    ready = true;
 | 
			
		||||
    run_all($$.before_update);
 | 
			
		||||
    // `false` as a special case of no DOM component
 | 
			
		||||
    $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
 | 
			
		||||
    if (options.target) {
 | 
			
		||||
        if (options.hydrate) {
 | 
			
		||||
            const nodes = children(options.target);
 | 
			
		||||
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | 
			
		||||
            $$.fragment && $$.fragment.l(nodes);
 | 
			
		||||
            nodes.forEach(detach);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | 
			
		||||
            $$.fragment && $$.fragment.c();
 | 
			
		||||
        }
 | 
			
		||||
        if (options.intro)
 | 
			
		||||
            transition_in(component.$$.fragment);
 | 
			
		||||
        mount_component(component, options.target, options.anchor, options.customElement);
 | 
			
		||||
        flush();
 | 
			
		||||
    }
 | 
			
		||||
    set_current_component(parent_component);
 | 
			
		||||
}
 | 
			
		||||
let SvelteElement;
 | 
			
		||||
if (typeof HTMLElement === 'function') {
 | 
			
		||||
    SvelteElement = class extends HTMLElement {
 | 
			
		||||
        constructor() {
 | 
			
		||||
            super();
 | 
			
		||||
            this.attachShadow({ mode: 'open' });
 | 
			
		||||
        }
 | 
			
		||||
        connectedCallback() {
 | 
			
		||||
            const { on_mount } = this.$$;
 | 
			
		||||
            this.$$.on_disconnect = on_mount.map(run).filter(is_function);
 | 
			
		||||
            // @ts-ignore todo: improve typings
 | 
			
		||||
            for (const key in this.$$.slotted) {
 | 
			
		||||
                // @ts-ignore todo: improve typings
 | 
			
		||||
                this.appendChild(this.$$.slotted[key]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        attributeChangedCallback(attr, _oldValue, newValue) {
 | 
			
		||||
            this[attr] = newValue;
 | 
			
		||||
        }
 | 
			
		||||
        disconnectedCallback() {
 | 
			
		||||
            run_all(this.$$.on_disconnect);
 | 
			
		||||
        }
 | 
			
		||||
        $destroy() {
 | 
			
		||||
            destroy_component(this, 1);
 | 
			
		||||
            this.$destroy = noop;
 | 
			
		||||
        }
 | 
			
		||||
        $on(type, callback) {
 | 
			
		||||
            // TODO should this delegate to addEventListener?
 | 
			
		||||
            if (!is_function(callback)) {
 | 
			
		||||
                return noop;
 | 
			
		||||
            }
 | 
			
		||||
            const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
 | 
			
		||||
            callbacks.push(callback);
 | 
			
		||||
            return () => {
 | 
			
		||||
                const index = callbacks.indexOf(callback);
 | 
			
		||||
                if (index !== -1)
 | 
			
		||||
                    callbacks.splice(index, 1);
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        $set($$props) {
 | 
			
		||||
            if (this.$$set && !is_empty($$props)) {
 | 
			
		||||
                this.$$.skip_bound = true;
 | 
			
		||||
                this.$$set($$props);
 | 
			
		||||
                this.$$.skip_bound = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dispatch_dev(type, detail) {
 | 
			
		||||
    document.dispatchEvent(custom_event(type, Object.assign({ version: '3.52.0' }, detail), { bubbles: true }));
 | 
			
		||||
}
 | 
			
		||||
function append_dev(target, node) {
 | 
			
		||||
    dispatch_dev('SvelteDOMInsert', { target, node });
 | 
			
		||||
    append(target, node);
 | 
			
		||||
}
 | 
			
		||||
function insert_dev(target, node, anchor) {
 | 
			
		||||
    dispatch_dev('SvelteDOMInsert', { target, node, anchor });
 | 
			
		||||
    insert(target, node, anchor);
 | 
			
		||||
}
 | 
			
		||||
function detach_dev(node) {
 | 
			
		||||
    dispatch_dev('SvelteDOMRemove', { node });
 | 
			
		||||
    detach(node);
 | 
			
		||||
}
 | 
			
		||||
function listen_dev(node, event, handler, options, has_prevent_default, has_stop_propagation) {
 | 
			
		||||
    const modifiers = options === true ? ['capture'] : options ? Array.from(Object.keys(options)) : [];
 | 
			
		||||
    if (has_prevent_default)
 | 
			
		||||
        modifiers.push('preventDefault');
 | 
			
		||||
    if (has_stop_propagation)
 | 
			
		||||
        modifiers.push('stopPropagation');
 | 
			
		||||
    dispatch_dev('SvelteDOMAddEventListener', { node, event, handler, modifiers });
 | 
			
		||||
    const dispose = listen(node, event, handler, options);
 | 
			
		||||
    return () => {
 | 
			
		||||
        dispatch_dev('SvelteDOMRemoveEventListener', { node, event, handler, modifiers });
 | 
			
		||||
        dispose();
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
function attr_dev(node, attribute, value) {
 | 
			
		||||
    attr(node, attribute, value);
 | 
			
		||||
    if (value == null)
 | 
			
		||||
        dispatch_dev('SvelteDOMRemoveAttribute', { node, attribute });
 | 
			
		||||
    else
 | 
			
		||||
        dispatch_dev('SvelteDOMSetAttribute', { node, attribute, value });
 | 
			
		||||
}
 | 
			
		||||
function prop_dev(node, property, value) {
 | 
			
		||||
    node[property] = value;
 | 
			
		||||
    dispatch_dev('SvelteDOMSetProperty', { node, property, value });
 | 
			
		||||
}
 | 
			
		||||
function set_data_dev(text, data) {
 | 
			
		||||
    data = '' + data;
 | 
			
		||||
    if (text.wholeText === data)
 | 
			
		||||
        return;
 | 
			
		||||
    dispatch_dev('SvelteDOMSetData', { node: text, data });
 | 
			
		||||
    text.data = data;
 | 
			
		||||
}
 | 
			
		||||
function validate_each_argument(arg) {
 | 
			
		||||
    if (typeof arg !== 'string' && !(arg && typeof arg === 'object' && 'length' in arg)) {
 | 
			
		||||
        let msg = '{#each} only iterates over array-like objects.';
 | 
			
		||||
        if (typeof Symbol === 'function' && arg && Symbol.iterator in arg) {
 | 
			
		||||
            msg += ' You can use a spread to convert this iterable into an array.';
 | 
			
		||||
        }
 | 
			
		||||
        throw new Error(msg);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function validate_slots(name, slot, keys) {
 | 
			
		||||
    for (const slot_key of Object.keys(slot)) {
 | 
			
		||||
        if (!~keys.indexOf(slot_key)) {
 | 
			
		||||
            console.warn(`<${name}> received an unexpected slot "${slot_key}".`);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { run_all as A, flush as B, is_function as C, src_url_equal as D, set_custom_element_data as E, prop_dev as F, set_style as G, svg_element as H, HtmlTag as I, afterUpdate as J, to_number as K, set_input_value as L, SvelteElement as S, attribute_to_object as a, insert_dev as b, validate_store as c, dispatch_dev as d, component_subscribe as e, globals as f, getContext as g, empty as h, init as i, detach_dev as j, binding_callbacks as k, validate_each_argument as l, space as m, noop as n, onMount as o, set_data_dev as p, element as q, add_location as r, safe_not_equal as s, text as t, attr_dev as u, validate_slots as v, append_dev as w, listen_dev as x, destroy_each as y, setContext as z };
 | 
			
		||||
							
								
								
									
										53
									
								
								Server/public/js/components/index-adbb0a76.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Server/public/js/components/index-adbb0a76.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
 | 
			
		||||
(function(l, r) { if (!l || l.getElementById('livereloadscript')) return; r = l.createElement('script'); r.async = 1; r.src = '//' + (self.location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1'; r.id = 'livereloadscript'; l.getElementsByTagName('head')[0].appendChild(r) })(self.document);
 | 
			
		||||
import { n as noop, s as safe_not_equal } from './index-2620635a.js';
 | 
			
		||||
 | 
			
		||||
const subscriber_queue = [];
 | 
			
		||||
/**
 | 
			
		||||
 * Create a `Writable` store that allows both updating and reading by subscription.
 | 
			
		||||
 * @param {*=}value initial value
 | 
			
		||||
 * @param {StartStopNotifier=}start start and stop notifications for subscriptions
 | 
			
		||||
 */
 | 
			
		||||
function writable(value, start = noop) {
 | 
			
		||||
    let stop;
 | 
			
		||||
    const subscribers = new Set();
 | 
			
		||||
    function set(new_value) {
 | 
			
		||||
        if (safe_not_equal(value, new_value)) {
 | 
			
		||||
            value = new_value;
 | 
			
		||||
            if (stop) { // store is ready
 | 
			
		||||
                const run_queue = !subscriber_queue.length;
 | 
			
		||||
                for (const subscriber of subscribers) {
 | 
			
		||||
                    subscriber[1]();
 | 
			
		||||
                    subscriber_queue.push(subscriber, value);
 | 
			
		||||
                }
 | 
			
		||||
                if (run_queue) {
 | 
			
		||||
                    for (let i = 0; i < subscriber_queue.length; i += 2) {
 | 
			
		||||
                        subscriber_queue[i][0](subscriber_queue[i + 1]);
 | 
			
		||||
                    }
 | 
			
		||||
                    subscriber_queue.length = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    function update(fn) {
 | 
			
		||||
        set(fn(value));
 | 
			
		||||
    }
 | 
			
		||||
    function subscribe(run, invalidate = noop) {
 | 
			
		||||
        const subscriber = [run, invalidate];
 | 
			
		||||
        subscribers.add(subscriber);
 | 
			
		||||
        if (subscribers.size === 1) {
 | 
			
		||||
            stop = start(set) || noop;
 | 
			
		||||
        }
 | 
			
		||||
        run(value);
 | 
			
		||||
        return () => {
 | 
			
		||||
            subscribers.delete(subscriber);
 | 
			
		||||
            if (subscribers.size === 0) {
 | 
			
		||||
                stop();
 | 
			
		||||
                stop = null;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    return { set, update, subscribe };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { writable as w };
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
 | 
			
		||||
using Genie.Router, Genie.Requests, Genie.Renderer.Json, JSON3, GenieAuthentication
 | 
			
		||||
using Server.GroupsController
 | 
			
		||||
using Genie.Router, Genie.Requests, Genie.Renderer.Json, JSON3, GenieAuthentication, GenieAuthorisation
 | 
			
		||||
using Server.GroupsController, Server.AdminController
 | 
			
		||||
 | 
			
		||||
#---Basic-----------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
@@ -12,6 +12,16 @@ route("/:locale/join-us/*", BasicController.join_us, named = :join_us)
 | 
			
		||||
 | 
			
		||||
route("/:locale/political-compass/*", BasicController.political_compass, named = :political_compass)
 | 
			
		||||
 | 
			
		||||
#---Admin panel------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
route("/:locale/bread/*", AdminController.admin_panel, named = :admin_panel)
 | 
			
		||||
 | 
			
		||||
route("/:locale/get-unverified-users/*", AdminController.get_unverified_users, named = :get_unverified_users)
 | 
			
		||||
 | 
			
		||||
route("/:locale/verify/*", AdminController.verify, method = POST, named=:verify)
 | 
			
		||||
 | 
			
		||||
route("/:locale/add-verified-groups/*", AdminController.add_verified_groups, named = :add_verified_groups)
 | 
			
		||||
 | 
			
		||||
#---Authentication and such------------------------------------------
 | 
			
		||||
 | 
			
		||||
route("/:locale/auth/*", AuthenticationController.auth, named = :auth)
 | 
			
		||||
@@ -54,8 +64,6 @@ route("/:locale/group-reject-request/*", GroupsController.reject_request, method
 | 
			
		||||
 | 
			
		||||
route("/:locale/group-change/*", GroupsController.change_group, method = POST, named = :group_change)
 | 
			
		||||
 | 
			
		||||
route("/:locale/add-verified-groups/*", GroupsController.add_verified_groups, named = :add_verified_groups)
 | 
			
		||||
 | 
			
		||||
#---Coops----------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
route("/:locale/cooperatives/*", CooperativesController.cooperatives, named = :cooperatives)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user