Compare commits
14 Commits
45a219625a
...
490b29295f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
490b29295f | ||
|
|
ded5e6ceb1 | ||
|
|
b81804439e | ||
|
|
9a9af9f002 | ||
|
|
cd495584b0 | ||
|
|
bbead3c43b | ||
|
|
ce18324391 | ||
|
|
c9d5a88dbf | ||
|
|
380fee09c1 | ||
|
|
e35524132e | ||
|
|
af000aa4bc | ||
|
|
90ed0925ca | ||
|
|
7c0a6fedb5 | ||
|
|
0e6edc8e65 |
44
frontend/src/app.d.ts
vendored
44
frontend/src/app.d.ts
vendored
@@ -68,12 +68,52 @@ interface User {
|
||||
notes: string | '';
|
||||
}
|
||||
|
||||
interface Car {
|
||||
id: number | -1;
|
||||
name: string | '';
|
||||
status: number | 0;
|
||||
brand: string | '';
|
||||
model: string | '';
|
||||
price: number | 0;
|
||||
rate: number | 0;
|
||||
start_date: string | '';
|
||||
end_date: string | '';
|
||||
color: string | '';
|
||||
licence_plate: string | '';
|
||||
location: Location;
|
||||
damages: Damage[] | [];
|
||||
insurances: Insurance[] | [];
|
||||
notes: string | '';
|
||||
}
|
||||
|
||||
interface Location {
|
||||
latitude: number | 0;
|
||||
longitude: number | 0;
|
||||
}
|
||||
|
||||
interface Damage {
|
||||
id: number | -1;
|
||||
opponent: User;
|
||||
insurance: Insurance | null;
|
||||
notes: string | '';
|
||||
}
|
||||
|
||||
interface Insurance {
|
||||
id: number | -1;
|
||||
company: string | '';
|
||||
reference: string | '';
|
||||
start_date: string | '';
|
||||
end_date: string | '';
|
||||
notes: string | '';
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
interface Locals {
|
||||
user: User;
|
||||
users: User[];
|
||||
cars: Cars[];
|
||||
subscriptions: Subscription[];
|
||||
licence_categories: LicenceCategory[];
|
||||
}
|
||||
@@ -84,6 +124,10 @@ declare global {
|
||||
licence: Licence;
|
||||
licenceCategory: LicenceCategory;
|
||||
bankAccount: BankAccount;
|
||||
car: Car;
|
||||
insurance: Insurance;
|
||||
location: Location;
|
||||
damage: Damage;
|
||||
}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
|
||||
252
frontend/src/lib/components/CarEditForm.svelte
Normal file
252
frontend/src/lib/components/CarEditForm.svelte
Normal file
@@ -0,0 +1,252 @@
|
||||
<script>
|
||||
import InputField from '$lib/components/InputField.svelte';
|
||||
import SmallLoader from '$lib/components/SmallLoader.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { applyAction, enhance } from '$app/forms';
|
||||
import { hasPrivilige, receive, send } from '$lib/utils/helpers';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { defaultCar } from '$lib/utils/defaults';
|
||||
import { PERMISSIONS } from '$lib/utils/constants';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
/** @type {import('../../routes/auth/about/[id]/$types').ActionData} */
|
||||
export let form;
|
||||
|
||||
/** @type {App.Locals['user'] } */
|
||||
export let editor;
|
||||
|
||||
/** @type {App.Types['car'] | null} */
|
||||
export let car;
|
||||
|
||||
console.log('Opening car modal with:', car);
|
||||
$: car = car || { ...defaultCar() };
|
||||
$: isLoading = car === undefined || editor === undefined;
|
||||
let isUpdating = false;
|
||||
let readonlyUser = !hasPrivilige(editor, PERMISSIONS.Update);
|
||||
|
||||
const TABS = ['car.car', 'insurance', 'car.damages'];
|
||||
let activeTab = TABS[0];
|
||||
|
||||
/** @type {import('../../routes/auth/about/[id]/$types').SubmitFunction} */
|
||||
const handleUpdate = async () => {
|
||||
isUpdating = true;
|
||||
return async ({ result }) => {
|
||||
isUpdating = false;
|
||||
if (result.type === 'success' || result.type === 'redirect') {
|
||||
dispatch('close');
|
||||
} else {
|
||||
document.querySelector('.modal .container')?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
await applyAction(result);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if isLoading}
|
||||
<SmallLoader width={30} message={$t('loading.car_data')} />
|
||||
{:else if editor && car}
|
||||
<form class="content" action="?/updateCar" method="POST" use:enhance={handleUpdate}>
|
||||
<input name="susbscription[id]" type="hidden" bind:value={car.id} />
|
||||
<h1 class="step-title" style="text-align: center;">
|
||||
{car.id ? $t('car.edit') : $t('car.create')}
|
||||
</h1>
|
||||
{#if form?.errors}
|
||||
{#each form?.errors as error (error.id)}
|
||||
<h4
|
||||
class="step-subtitle warning"
|
||||
in:receive|global={{ key: error.id }}
|
||||
out:send|global={{ key: error.id }}
|
||||
>
|
||||
{$t(error.field) + ': ' + $t(error.key)}
|
||||
</h4>
|
||||
{/each}
|
||||
{/if}
|
||||
<div class="button-container">
|
||||
{#each TABS as tab}
|
||||
<button
|
||||
type="button"
|
||||
class="button-dark"
|
||||
class:active={activeTab === tab}
|
||||
on:click={() => (activeTab = tab)}
|
||||
>
|
||||
{$t(tab)}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tab-content" style="display: {activeTab === 'car.car' ? 'block' : 'none'}">
|
||||
<InputField
|
||||
name="car[name]"
|
||||
label={$t('name')}
|
||||
bind:value={car.name}
|
||||
placeholder={$t('placeholder.car_name')}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[brand]"
|
||||
label={$t('car.brand')}
|
||||
bind:value={car.brand}
|
||||
placeholder={$t('placeholder.car_brand')}
|
||||
required={true}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[model]"
|
||||
label={$t('car.model')}
|
||||
bind:value={car.model}
|
||||
placeholder={$t('placeholder.car_model')}
|
||||
required={true}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[color]"
|
||||
label={$t('color')}
|
||||
bind:value={car.color}
|
||||
placeholder={$t('placeholder.car_color')}
|
||||
required={true}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[licence_plate]"
|
||||
label={$t('car.licence_plate')}
|
||||
bind:value={car.licence_plate}
|
||||
placeholder={$t('placeholder.car_licence_plate')}
|
||||
required={true}
|
||||
toUpperCase={true}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[price]"
|
||||
type="number"
|
||||
label={$t('price')}
|
||||
bind:value={car.price}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[rate]"
|
||||
type="number"
|
||||
label={$t('car.leasing_rate')}
|
||||
bind:value={car.rate}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[start_date]"
|
||||
type="date"
|
||||
label={$t('car.start_date')}
|
||||
bind:value={car.start_date}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[end_date]"
|
||||
type="date"
|
||||
label={$t('car.end_date')}
|
||||
bind:value={car.end_date}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[notes]"
|
||||
type="textarea"
|
||||
label={$t('notes')}
|
||||
bind:value={car.notes}
|
||||
placeholder={$t('placeholder.notes', {
|
||||
values: { name: car.name || car.brand + ' ' + car.model }
|
||||
})}
|
||||
rows={10}
|
||||
/>
|
||||
</div>
|
||||
<div class="tab-content" style="display: {activeTab === 'insurance' ? 'block' : 'none'}">
|
||||
{#each car.insurances as insurance}
|
||||
<InputField
|
||||
name="car[insurance][company]"
|
||||
label={$t('company')}
|
||||
bind:value={insurance.company}
|
||||
placeholder={$t('placeholder.company')}
|
||||
required={true}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[insurance][reference]"
|
||||
label={$t('insurance.reference')}
|
||||
bind:value={insurance.reference}
|
||||
placeholder={$t('placeholder.insurance_reference')}
|
||||
required={true}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[insurance][start_date]"
|
||||
type="date"
|
||||
label={$t('start')}
|
||||
bind:value={insurance.start_date}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[insurance][end_date]"
|
||||
type="date"
|
||||
label={$t('end')}
|
||||
bind:value={insurance.end_date}
|
||||
readonly={readonlyUser}
|
||||
/>
|
||||
<InputField
|
||||
name="car[insurance][notes]"
|
||||
type="textarea"
|
||||
label={$t('notes')}
|
||||
bind:value={insurance.notes}
|
||||
placeholder={$t('placeholder.notes', {
|
||||
values: { name: insurance.company || '' }
|
||||
})}
|
||||
rows={10}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="button-container">
|
||||
{#if isUpdating}
|
||||
<SmallLoader width={30} message={$t('loading.updating')} />
|
||||
{:else}
|
||||
<button type="button" class="button-dark" on:click={() => dispatch('cancel')}>
|
||||
{$t('cancel')}</button
|
||||
>
|
||||
<button type="submit" class="button-dark">{$t('confirm')}</button>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.tab-content {
|
||||
padding: 1rem;
|
||||
border-radius: 0 0 3px 3px;
|
||||
background-color: var(--surface0);
|
||||
border: 1px solid var(--surface1);
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button-container button {
|
||||
flex: 1 1 0;
|
||||
min-width: 120px;
|
||||
max-width: calc(50% - 5px);
|
||||
background-color: var(--surface1);
|
||||
color: var(--text);
|
||||
border: 1px solid var(--overlay0);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.button-container button:hover {
|
||||
background-color: var(--surface2);
|
||||
border-color: var(--lavender);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.button-container button {
|
||||
flex-basis: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,6 +5,7 @@
|
||||
import { applyAction, enhance } from '$app/forms';
|
||||
import { receive, send } from '$lib/utils/helpers';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { defaultSubscription } from '$lib/utils/defaults';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
@@ -17,20 +18,8 @@
|
||||
/** @type {App.Types['subscription'] | null} */
|
||||
export let subscription;
|
||||
|
||||
/** @type {App.Types['subscription']} */
|
||||
const blankSubscription = {
|
||||
id: 0,
|
||||
name: '',
|
||||
details: '',
|
||||
conditions: '',
|
||||
monthly_fee: 0,
|
||||
hourly_rate: 0,
|
||||
included_hours_per_year: 0,
|
||||
included_hours_per_month: 0
|
||||
};
|
||||
|
||||
console.log('Opening subscription modal with:', subscription);
|
||||
$: subscription = subscription || { ...blankSubscription };
|
||||
$: subscription = subscription || { ...defaultSubscription() };
|
||||
$: isLoading = subscription === undefined || user === undefined;
|
||||
let isUpdating = false;
|
||||
|
||||
|
||||
@@ -11,9 +11,15 @@ export default {
|
||||
1: 'Mitglied',
|
||||
2: 'Betrachter',
|
||||
4: 'Bearbeiter',
|
||||
8: 'Administrator'
|
||||
8: 'Adm/endinistrator'
|
||||
},
|
||||
placeholder: {
|
||||
car_name: 'Hat das Fahrzeug einen Namen?',
|
||||
car_brand: 'Fahrzeughersteller eingeben...',
|
||||
car_model: 'Fahrzeugmodell eingeben...',
|
||||
car_color: 'Fahrzeugfarbe eingeben...',
|
||||
car_licence_plate: 'Fahrzeugkennzeichen eingeben...',
|
||||
insurance_reference: 'Versicherungsnummer eingeben...',
|
||||
password: 'Passwort eingeben...',
|
||||
email: 'Emailadresse eingeben...',
|
||||
company: 'Firmennamen eingeben...',
|
||||
@@ -147,15 +153,29 @@ export default {
|
||||
included_hours_per_year: 'Inkludierte Stunden pro Jahr',
|
||||
included_hours_per_month: 'Inkludierte Stunden pro Monat'
|
||||
},
|
||||
car: {
|
||||
car: 'Fahrzeug',
|
||||
model: 'Modell',
|
||||
brand: 'Marke',
|
||||
licence_plate: 'Kennzeichen',
|
||||
edit: 'Fahrzeug bearbeiten',
|
||||
create: 'Fahrzeug hinzufügen',
|
||||
damages: 'Schäden',
|
||||
start_date: 'Anschaffungsdatum',
|
||||
end_date: 'Leasingende',
|
||||
leasing_rate: 'Leasingrate'
|
||||
},
|
||||
loading: {
|
||||
user_data: 'Lade Nutzerdaten',
|
||||
subscription_data: 'Lade Modelldaten',
|
||||
car_data: 'Lade Fahrzeugdaten',
|
||||
please_wait: 'Bitte warten...',
|
||||
updating: 'Aktualisiere...'
|
||||
},
|
||||
dialog: {
|
||||
user_deletion: 'Soll der Nutzer {firstname} {lastname} wirklich gelöscht werden?',
|
||||
subscription_deletion: 'Soll das Tarifmodell {name} wirklich gelöscht werden?',
|
||||
car_deletion: 'Soll das Fahrzeug {name} wirklich gelöscht werden?',
|
||||
backend_access: 'Soll {firstname} {lastname} Backend Zugriff gewährt werden?'
|
||||
},
|
||||
cancel: 'Abbrechen',
|
||||
@@ -165,14 +185,20 @@ export default {
|
||||
delete: 'Löschen',
|
||||
search: 'Suche:',
|
||||
name: 'Name',
|
||||
price: 'Preis',
|
||||
color: 'Farbe',
|
||||
grant_backend_access: 'Backend Zugriff gewähren',
|
||||
no_insurance: 'Keine Versicherung',
|
||||
supporter: 'Sponsoren',
|
||||
mandate_date_signed: 'Mandatserteilungsdatum',
|
||||
licence_categories: 'Führerscheinklassen',
|
||||
subscription_model: 'Mitgliedschatfsmodell',
|
||||
licence: 'Führerschein',
|
||||
licence_number: 'Führerscheinnummer',
|
||||
insurance: 'Versicherung',
|
||||
insurance_reference: 'Versicherungsnummer',
|
||||
issued_date: 'Ausgabedatum',
|
||||
month: 'Monat',
|
||||
expiration_date: 'Ablaufdatum',
|
||||
country: 'Land',
|
||||
details: 'Details',
|
||||
@@ -191,6 +217,7 @@ export default {
|
||||
company: 'Firma',
|
||||
login: 'Anmeldung',
|
||||
profile: 'Profil',
|
||||
cars: 'Fahrzeuge',
|
||||
membership: 'Mitgliedschaft',
|
||||
bankaccount: 'Kontodaten',
|
||||
status: 'Status',
|
||||
|
||||
@@ -30,7 +30,7 @@ export default {
|
||||
bic: 'Enter BIC (for non-German accounts)...',
|
||||
mandate_reference: 'Enter SEPA mandate reference...',
|
||||
notes: 'Your notes about {name}...',
|
||||
licence_number: 'On the driver’s license under field 5',
|
||||
licence_number: 'On the driver’s licence under field 5',
|
||||
issued_date: 'Issue date under field 4a',
|
||||
expiration_date: 'Expiration date under field 4b',
|
||||
issuing_country: 'Issuing country',
|
||||
@@ -81,7 +81,7 @@ export default {
|
||||
bic: 'Invalid. Format: BELADEBEXXX',
|
||||
email: 'Invalid format',
|
||||
number: 'Is not a number',
|
||||
euDriversLicence: 'Is not a European driver’s license',
|
||||
euDriversLicence: 'Is not a European driver’s licence',
|
||||
lte: 'Is too large/new',
|
||||
gt: 'Is too small/old',
|
||||
required: 'Field is required',
|
||||
@@ -159,10 +159,10 @@ export default {
|
||||
name: 'Name',
|
||||
supporter: 'Sponsors',
|
||||
mandate_date_signed: 'Mandate Signing Date',
|
||||
licence_categories: 'Driver’s License Categories',
|
||||
licence_categories: 'Driver’s licence Categories',
|
||||
subscription_model: 'Membership Model',
|
||||
licence: 'Driver’s License',
|
||||
licence_number: 'Driver’s License Number',
|
||||
licence: 'Driver’s licence',
|
||||
licence_number: 'Driver’s licence Number',
|
||||
issued_date: 'Issue Date',
|
||||
expiration_date: 'Expiration Date',
|
||||
country: 'Country',
|
||||
|
||||
@@ -117,3 +117,62 @@ export function defaultSupporter() {
|
||||
supporter.membership.subscription_model.name = SUPPORTER_SUBSCRIPTION_MODEL_NAME;
|
||||
return supporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {App.Types['location']}
|
||||
*/
|
||||
export function defaultLocation() {
|
||||
return {
|
||||
latitude: 0,
|
||||
longitude: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {App.Types['damage']}
|
||||
*/
|
||||
export function defaultDamage() {
|
||||
return {
|
||||
id: 0,
|
||||
opponent: defaultUser(),
|
||||
insurance: null,
|
||||
notes: ''
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {App.Types['insurance']}
|
||||
*/
|
||||
export function defaultInsurance() {
|
||||
return {
|
||||
id: 0,
|
||||
company: '',
|
||||
reference: '',
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
notes: ''
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {App.Types['car']}
|
||||
*/
|
||||
export function defaultCar() {
|
||||
return {
|
||||
id: 0,
|
||||
name: '',
|
||||
status: '',
|
||||
brand: '',
|
||||
model: '',
|
||||
price: 0,
|
||||
rate: 0,
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
color: '',
|
||||
licence_plate: '',
|
||||
location: defaultLocation(),
|
||||
damages: [],
|
||||
insurances: [],
|
||||
notes: ''
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,6 +88,31 @@ export function fromRFC3339(dateString) {
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {App.Types['car']} car - The car object to format
|
||||
*/
|
||||
export function carDatesFromRFC3339(car) {
|
||||
car.end_date = fromRFC3339(car.end_date);
|
||||
car.start_date = fromRFC3339(car.start_date);
|
||||
car.insurances?.forEach((insurance) => {
|
||||
insurance.start_date = fromRFC3339(insurance.start_date);
|
||||
insurance.end_date = fromRFC3339(insurance.end_date);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {App.Types['car']} car - The car object to format
|
||||
*/
|
||||
export function carDatesToRFC3339(car) {
|
||||
car.end_date = toRFC3339(car.end_date);
|
||||
car.start_date = toRFC3339(car.start_date);
|
||||
car.insurances?.forEach((insurance) => {
|
||||
insurance.start_date = toRFC3339(insurance.start_date);
|
||||
insurance.end_date = toRFC3339(insurance.end_date);
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {App.Locals['user']} user - The user object to format
|
||||
|
||||
@@ -3,10 +3,10 @@ import { toRFC3339 } from './helpers';
|
||||
/**
|
||||
* Converts FormData to a nested object structure
|
||||
* @param {FormData} formData - The FormData object to convert
|
||||
* @returns {{ object: Partial<App.Locals['user']> | Partial<App.Types['subscription']>, confirm_password: string }} Nested object representation of the form data
|
||||
* @returns {{ object: Partial<App.Locals['user']> | Partial<App.Types['subscription']> | Partial<App.Types['car']>, confirm_password: string }} Nested object representation of the form data
|
||||
*/
|
||||
export function formDataToObject(formData) {
|
||||
/** @type { Partial<App.Locals['user']> | Partial<App.Types['subscription']> } */
|
||||
/** @type { Partial<App.Locals['user']> | Partial<App.Types['subscription']> | Partial<App.Types['car']> } */
|
||||
const object = {};
|
||||
let confirm_password = '';
|
||||
|
||||
@@ -142,8 +142,8 @@ export function processUserFormData(rawData) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the raw form data into the expected user data structure
|
||||
* @param {{ object: Partial<App.Types['subscription']>} } rawData - The raw form data object
|
||||
* Processes the raw form data into the expected subscription data structure
|
||||
* @param {{ object: Partial<App.Types['subscription']>, confirm_password: string }} rawData - The raw form data object
|
||||
* @returns {{ subscription: Partial<App.Types['subscription']> }} Processed user data
|
||||
*/
|
||||
export function processSubscriptionFormData(rawData) {
|
||||
@@ -166,3 +166,39 @@ export function processSubscriptionFormData(rawData) {
|
||||
console.dir(clean);
|
||||
return clean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the raw form data into the expected car data structure
|
||||
* @param {{ object: Partial<App.Types['car']>, confirm_password: string }} rawData - The raw form data object
|
||||
* @returns {{ car: Partial<App.Types['car']> }} Processed user data
|
||||
*/
|
||||
export function processCarFormData(rawData) {
|
||||
/** @type {{ car: Partial<App.Types['car']> }} */
|
||||
let processedData = {
|
||||
car: {
|
||||
id: Number(rawData.object.id) || 0,
|
||||
name: String(rawData.object.name) || '',
|
||||
status: Number(rawData.object.status) || 0,
|
||||
brand: String(rawData.object.brand) || '',
|
||||
model: String(rawData.object.model) || '',
|
||||
price: Number(rawData.object.price) || 0,
|
||||
rate: Number(rawData.object.rate) || 0,
|
||||
licence_plate: String(rawData.object.licence_plate) || '',
|
||||
start_date: toRFC3339(String(rawData.object.start_date)) || '',
|
||||
end_date: toRFC3339(String(rawData.object.end_date)) || '',
|
||||
color: String(rawData.object.color) || '',
|
||||
notes: String(rawData.object.notes) || '',
|
||||
location: {
|
||||
latitude: Number(rawData.object.location?.latitude) || 0,
|
||||
longitude: Number(rawData.object.location?.longitude) || 0
|
||||
},
|
||||
damages: rawData.object.damages || [],
|
||||
insurances: rawData.object.insurances || []
|
||||
}
|
||||
};
|
||||
const clean = JSON.parse(JSON.stringify(processedData), (key, value) =>
|
||||
value !== null && value !== '' ? value : undefined
|
||||
);
|
||||
console.dir(clean);
|
||||
return clean;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
export async function load({ data }) {
|
||||
return {
|
||||
users: data.users,
|
||||
user: data.user
|
||||
user: data.user,
|
||||
cars: data.cars
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,43 +1,63 @@
|
||||
import { BASE_API_URI } from '$lib/utils/constants';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { userDatesFromRFC3339, refreshCookie } from '$lib/utils/helpers';
|
||||
import { userDatesFromRFC3339, refreshCookie, carDatesFromRFC3339 } from '$lib/utils/helpers';
|
||||
import { base } from '$app/paths';
|
||||
|
||||
/** @type {import('./$types').LayoutServerLoad} */
|
||||
export async function load({ cookies, fetch, locals }) {
|
||||
const jwt = cookies.get('jwt');
|
||||
try {
|
||||
const response = await fetch(`${BASE_API_URI}/auth/users/`, {
|
||||
const [usersResponse, carsResponse] = await Promise.all([
|
||||
fetch(`${BASE_API_URI}/auth/users`, {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
Cookie: `jwt=${jwt}`
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
// Clear the invalid JWT cookie
|
||||
headers: { Cookie: `jwt=${jwt}` }
|
||||
}),
|
||||
fetch(`${BASE_API_URI}/auth/cars`, {
|
||||
credentials: 'include',
|
||||
headers: { Cookie: `jwt=${jwt}` }
|
||||
})
|
||||
]);
|
||||
if (!usersResponse.ok || !carsResponse.ok) {
|
||||
cookies.delete('jwt', { path: '/' });
|
||||
throw redirect(302, `${base}/auth/login?next=${base}/auth/admin/users/`);
|
||||
}
|
||||
const [usersData, carsData] = await Promise.all([usersResponse.json(), carsResponse.json()]);
|
||||
// const response = await fetch(`${BASE_API_URI}/auth/users/`, {
|
||||
// credentials: 'include',
|
||||
// headers: {
|
||||
// Cookie: `jwt=${jwt}`
|
||||
// }
|
||||
// });
|
||||
// if (!response.ok) {
|
||||
// // Clear the invalid JWT cookie
|
||||
// cookies.delete('jwt', { path: '/' });
|
||||
// throw redirect(302, `${base}/auth/login?next=${base}/auth/admin/users/`);
|
||||
// }
|
||||
|
||||
const data = await response.json();
|
||||
// const data = await response.json();
|
||||
/** @type {App.Locals['users']}*/
|
||||
const users = data.users;
|
||||
const users = usersData.users;
|
||||
/** @type {App.Types['car'][]} */
|
||||
const cars = carsData.cars;
|
||||
|
||||
users.forEach((user) => {
|
||||
userDatesFromRFC3339(user);
|
||||
});
|
||||
cars.forEach((car) => {
|
||||
carDatesFromRFC3339(car);
|
||||
});
|
||||
|
||||
locals.users = users;
|
||||
|
||||
locals.cars = cars;
|
||||
// Check if the server sent a new token
|
||||
const newToken = response.headers.get('Set-Cookie');
|
||||
const newToken = usersResponse.headers.get('Set-Cookie');
|
||||
refreshCookie(newToken, cookies);
|
||||
|
||||
return {
|
||||
subscriptions: locals.subscriptions,
|
||||
licence_categories: locals.licence_categories,
|
||||
users: locals.users,
|
||||
user: locals.user
|
||||
user: locals.user,
|
||||
cars: locals.cars
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { formatError, hasPrivilige, userDatesFromRFC3339 } from '$lib/utils/help
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import {
|
||||
formDataToObject,
|
||||
processCarFormData,
|
||||
processSubscriptionFormData,
|
||||
processUserFormData
|
||||
} from '$lib/utils/processing';
|
||||
@@ -36,7 +37,12 @@ export const actions = {
|
||||
updateUser: async ({ request, fetch, cookies, locals }) => {
|
||||
let formData = await request.formData();
|
||||
|
||||
const rawData = formDataToObject(formData);
|
||||
const rawFormData = formDataToObject(formData);
|
||||
/** @type {{object: Partial<App.Locals['user']>, confirm_password: string}} */
|
||||
const rawData = {
|
||||
object: /** @type {Partial<App.Locals['user']>} */ (rawFormData.object),
|
||||
confirm_password: rawFormData.confirm_password
|
||||
};
|
||||
const processedData = processUserFormData(rawData);
|
||||
|
||||
console.dir(processedData.user.membership);
|
||||
@@ -96,7 +102,55 @@ export const actions = {
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: `jwt=${cookies.get('jwt')}`
|
||||
},
|
||||
body: JSON.stringify(processedData)
|
||||
body: JSON.stringify(processedData.subscription)
|
||||
};
|
||||
|
||||
const res = await fetch(apiURL, requestOptions);
|
||||
|
||||
if (!res.ok) {
|
||||
const response = await res.json();
|
||||
const errors = formatError(response.errors);
|
||||
return fail(400, { errors: errors });
|
||||
}
|
||||
|
||||
const response = await res.json();
|
||||
console.log('Server success response:', response);
|
||||
throw redirect(303, `${base}/auth/admin/users`);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param request - The request object
|
||||
* @param fetch - Fetch object from sveltekit
|
||||
* @param cookies - SvelteKit's cookie object
|
||||
* @returns Error data or redirects user to the home page or the previous page
|
||||
*/
|
||||
updateCar: async ({ request, fetch, cookies }) => {
|
||||
let formData = await request.formData();
|
||||
|
||||
const rawFormData = formDataToObject(formData);
|
||||
/** @type {{object: Partial<App.Types['car']>, confirm_password: string}} */
|
||||
const rawData = {
|
||||
object: /** @type {Partial<App.Types['car']>} */ (rawFormData.object),
|
||||
confirm_password: rawFormData.confirm_password
|
||||
};
|
||||
const processedData = processCarFormData(rawData);
|
||||
|
||||
const isCreating = !processedData.car.id || processedData.car.id === 0;
|
||||
console.log('Is creating: ', isCreating);
|
||||
console.log('sending: ', JSON.stringify(processedData.car));
|
||||
|
||||
const apiURL = `${BASE_API_URI}/auth/cars`;
|
||||
|
||||
/** @type {RequestInit} */
|
||||
const requestOptions = {
|
||||
method: isCreating ? 'POST' : 'PUT',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: `jwt=${cookies.get('jwt')}`
|
||||
},
|
||||
body: JSON.stringify(processedData.car)
|
||||
};
|
||||
|
||||
const res = await fetch(apiURL, requestOptions);
|
||||
@@ -123,7 +177,12 @@ export const actions = {
|
||||
userDelete: async ({ request, fetch, cookies }) => {
|
||||
let formData = await request.formData();
|
||||
|
||||
const rawData = formDataToObject(formData);
|
||||
const rawFormData = formDataToObject(formData);
|
||||
/** @type {{object: Partial<App.Locals['user']>, confirm_password: string}} */
|
||||
const rawData = {
|
||||
object: /** @type {Partial<App.Locals['user']>} */ (rawFormData.object),
|
||||
confirm_password: rawFormData.confirm_password
|
||||
};
|
||||
const processedData = processUserFormData(rawData);
|
||||
|
||||
const apiURL = `${BASE_API_URI}/auth/users`;
|
||||
@@ -176,7 +235,7 @@ export const actions = {
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: `jwt=${cookies.get('jwt')}`
|
||||
},
|
||||
body: JSON.stringify(processedData)
|
||||
body: JSON.stringify(processedData.subscription)
|
||||
};
|
||||
|
||||
const res = await fetch(apiURL, requestOptions);
|
||||
@@ -191,10 +250,23 @@ export const actions = {
|
||||
console.log('Server success response:', response);
|
||||
throw redirect(303, `${base}/auth/admin/users`);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param request - The request object
|
||||
* @param fetch - Fetch object from sveltekit
|
||||
* @param cookies - SvelteKit's cookie object
|
||||
* @returns
|
||||
*/
|
||||
grantBackendAccess: async ({ request, fetch, cookies }) => {
|
||||
let formData = await request.formData();
|
||||
|
||||
const rawData = formDataToObject(formData);
|
||||
const rawFormData = formDataToObject(formData);
|
||||
/** @type {{object: Partial<App.Types['subscription']>, confirm_password: string}} */
|
||||
const rawData = {
|
||||
object: /** @type {Partial<App.Types['subscription']>} */ (rawFormData.object),
|
||||
confirm_password: rawFormData.confirm_password
|
||||
};
|
||||
const processedData = processUserFormData(rawData);
|
||||
console.dir(processedData);
|
||||
const apiURL = `${BASE_API_URI}/auth/users/activate`;
|
||||
|
||||
@@ -8,7 +8,13 @@
|
||||
import { applyAction, enhance } from '$app/forms';
|
||||
import { hasPrivilige, receive, send } from '$lib/utils/helpers';
|
||||
import { PERMISSIONS } from '$lib/utils/constants';
|
||||
import { defaultSupporter, defaultUser } from '$lib/utils/defaults';
|
||||
import {
|
||||
defaultCar,
|
||||
defaultSubscription,
|
||||
defaultSupporter,
|
||||
defaultUser
|
||||
} from '$lib/utils/defaults';
|
||||
import CarEditForm from '$lib/components/CarEditForm.svelte';
|
||||
|
||||
/** @type {import('./$types').ActionData} */
|
||||
export let form;
|
||||
@@ -16,18 +22,17 @@
|
||||
$: ({
|
||||
user = [],
|
||||
users = [],
|
||||
cars = [],
|
||||
licence_categories = [],
|
||||
subscriptions = [],
|
||||
payments = []
|
||||
} = $page.data);
|
||||
|
||||
let activeSection = 'members';
|
||||
/** @type{App.Locals['user'] | null} */
|
||||
let selectedUser = null;
|
||||
/** @type{App.Types['subscription'] | null} */
|
||||
let selectedSubscription = null;
|
||||
let showSubscriptionModal = false;
|
||||
let showUserModal = false;
|
||||
|
||||
/** @type{App.Types['car'] | App.Types['subscription'] | App.Locals['user'] | null} */
|
||||
let selected = null;
|
||||
|
||||
let searchTerm = '';
|
||||
|
||||
$: members = users.filter((/** @type{App.Locals['user']} */ user) => {
|
||||
@@ -95,29 +100,8 @@
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the edit modal for the selected user.
|
||||
* @param {App.Locals['user']} user The user to edit.
|
||||
*/
|
||||
const openEditUserModal = (user) => {
|
||||
selectedUser = user;
|
||||
showUserModal = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the edit modal for the selected subscription.
|
||||
* @param {App.Types['subscription'] | null} subscription The user to edit.
|
||||
*/
|
||||
const openEditSubscriptionModal = (subscription) => {
|
||||
selectedSubscription = subscription;
|
||||
showSubscriptionModal = true;
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
showUserModal = false;
|
||||
showSubscriptionModal = false;
|
||||
selectedUser = null;
|
||||
selectedSubscription = null;
|
||||
selected = null;
|
||||
if (form) {
|
||||
form.errors = [];
|
||||
}
|
||||
@@ -167,6 +151,16 @@
|
||||
<span class="nav-badge">{subscriptions.length}</span>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="nav-link {activeSection === 'cars' ? 'active' : ''}"
|
||||
on:click={() => setActiveSection('cars')}
|
||||
>
|
||||
<i class="fas fa-car"></i>
|
||||
{$t('cars')}
|
||||
<span class="nav-badge">{cars.length}</span>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="nav-link {activeSection === 'payments' ? 'active' : ''}"
|
||||
@@ -214,7 +208,12 @@
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn primary" on:click={() => openEditUserModal(defaultUser())}>
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = defaultUser();
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-plus"></i>
|
||||
{$t('add_new')}
|
||||
</button>
|
||||
@@ -288,7 +287,12 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="button-group">
|
||||
<button class="btn primary" on:click={() => openEditUserModal(user)}>
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = user;
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-edit"></i>
|
||||
{$t('edit')}
|
||||
</button>
|
||||
@@ -350,7 +354,12 @@
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn primary" on:click={() => openEditUserModal(defaultSupporter())}>
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = defaultSupporter();
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-plus"></i>
|
||||
{$t('add_new')}
|
||||
</button>
|
||||
@@ -384,7 +393,12 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="button-group">
|
||||
<button class="btn primary" on:click={() => openEditUserModal(user)}>
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = user;
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-edit"></i>
|
||||
{$t('edit')}
|
||||
</button>
|
||||
@@ -429,7 +443,12 @@
|
||||
<div class="section-header">
|
||||
<h2>{$t('subscription.subscriptions')}</h2>
|
||||
{#if hasPrivilige(user, PERMISSIONS.Super)}
|
||||
<button class="btn primary" on:click={() => openEditSubscriptionModal(null)}>
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = defaultSubscription();
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-plus"></i>
|
||||
{$t('add_new')}
|
||||
</button>
|
||||
@@ -488,7 +507,9 @@
|
||||
<div class="button-group">
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => openEditSubscriptionModal(subscription)}
|
||||
on:click={() => {
|
||||
selected = subscription;
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-edit"></i>
|
||||
{$t('edit')}
|
||||
@@ -537,6 +558,112 @@
|
||||
</details>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if activeSection === 'cars'}
|
||||
<div class="section-header">
|
||||
<h2>{$t('cars')}</h2>
|
||||
{#if hasPrivilige(user, PERMISSIONS.Super)}
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = defaultCar();
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-plus"></i>
|
||||
{$t('add_new')}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="accordion">
|
||||
{#each cars as car}
|
||||
<details class="accordion-item">
|
||||
<summary class="accordion-header">
|
||||
{car.model + ' (' + car.licence_plate + ')'}
|
||||
</summary>
|
||||
<div class="accordion-content">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{$t('car.model')}</th>
|
||||
<td>{car.brand + ' ' + car.model + ' (' + car.color + ')'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$t('price')}</th>
|
||||
<td
|
||||
>{car.price + '€'}{car.rate
|
||||
? ' + ' + car.rate + '€/' + $t('month')
|
||||
: ''}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$t('car.damages')}</th>
|
||||
<td>{car.damages?.length || 0}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$t('insurance')}</th>
|
||||
<td
|
||||
>{car.insurance
|
||||
? car.insurance.company + '(' + car.insurance.reference + ')'
|
||||
: '-'}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$t('car.end_date')}</th>
|
||||
<td>{car.end_date || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{#if hasPrivilige(user, PERMISSIONS.Update)}
|
||||
<div class="button-group">
|
||||
<button
|
||||
class="btn primary"
|
||||
on:click={() => {
|
||||
selected = car;
|
||||
}}
|
||||
>
|
||||
<i class="fas fa-edit"></i>
|
||||
{$t('edit')}
|
||||
</button>
|
||||
<form
|
||||
method="POST"
|
||||
action="?/carDelete"
|
||||
use:enhance={() => {
|
||||
return async ({ result }) => {
|
||||
if (result.type === 'success' || result.type === 'redirect') {
|
||||
await applyAction(result);
|
||||
} else {
|
||||
document
|
||||
.querySelector('.accordion-content')
|
||||
?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
await applyAction(result);
|
||||
}
|
||||
};
|
||||
}}
|
||||
on:submit|preventDefault={(/** @type {SubmitEvent} */ e) => {
|
||||
if (
|
||||
!confirm(
|
||||
$t('dialog.car_deletion', {
|
||||
values: {
|
||||
name: car.brand + ' ' + car.model + ' (' + car.licence_plate + ')'
|
||||
}
|
||||
})
|
||||
)
|
||||
) {
|
||||
e.preventDefault(); // Cancel form submission if user declines
|
||||
}
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="subscription[id]" value={car.id} />
|
||||
<button class="btn danger" type="submit">
|
||||
<i class="fas fa-trash"></i>
|
||||
{$t('delete')}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</details>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if activeSection === 'payments'}
|
||||
<h2>{$t('payments')}</h2>
|
||||
<div class="accordion">
|
||||
@@ -567,28 +694,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showUserModal && selectedUser !== null}
|
||||
{#if selected && 'email' in selected}
|
||||
// user
|
||||
<Modal on:close={close}>
|
||||
<UserEditForm
|
||||
{form}
|
||||
editor={user}
|
||||
user={selectedUser}
|
||||
user={selected}
|
||||
{subscriptions}
|
||||
{licence_categories}
|
||||
on:cancel={close}
|
||||
on:close={close}
|
||||
/>
|
||||
</Modal>
|
||||
{:else if showSubscriptionModal}
|
||||
{:else if selected && 'monthly_fee' in selected}
|
||||
//subscription
|
||||
<Modal on:close={close}>
|
||||
<SubscriptionEditForm
|
||||
{form}
|
||||
{user}
|
||||
subscription={selectedSubscription}
|
||||
subscription={selected}
|
||||
on:cancel={close}
|
||||
on:close={close}
|
||||
/>
|
||||
</Modal>
|
||||
{:else if selected && 'brand' in selected}
|
||||
<Modal on:close={close}>
|
||||
<CarEditForm {form} editor={user} car={selected} on:cancel={close} on:close={close} />
|
||||
</Modal>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
118
go-backend/internal/controllers/car_controller.go
Normal file
118
go-backend/internal/controllers/car_controller.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"GoMembership/internal/constants"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/services"
|
||||
"GoMembership/internal/utils"
|
||||
"GoMembership/pkg/errors"
|
||||
"GoMembership/pkg/logger"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CarController struct {
|
||||
S services.CarServiceInterface
|
||||
UserService services.UserServiceInterface
|
||||
}
|
||||
|
||||
func (cr *CarController) Create(c *gin.Context) {
|
||||
requestUser, err := cr.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error extracting user from context in Create car handler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
|
||||
return
|
||||
}
|
||||
if !requestUser.HasPrivilege(constants.Priviliges.Create) {
|
||||
utils.RespondWithError(c, errors.ErrNotAuthorized, fmt.Sprintf("Not allowed to create a car. RoleID(%v)<Privilige(%v)", requestUser.RoleID, constants.Priviliges.Create), http.StatusUnauthorized, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
|
||||
return
|
||||
}
|
||||
var newCar models.Car
|
||||
if err := c.ShouldBindJSON(&newCar); err != nil {
|
||||
utils.HandleValidationError(c, err)
|
||||
return
|
||||
}
|
||||
car, err := cr.S.Create(&newCar)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error creating car", http.StatusInternalServerError, errors.Responses.Fields.Car, errors.Responses.Keys.InternalServerError)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, car)
|
||||
}
|
||||
|
||||
func (cr *CarController) Update(c *gin.Context) {
|
||||
requestUser, err := cr.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error extracting user from context in Update car handler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
|
||||
return
|
||||
}
|
||||
if !requestUser.HasPrivilege(constants.Priviliges.Update) {
|
||||
utils.RespondWithError(c, errors.ErrNotAuthorized, fmt.Sprintf("Not allowed to update a car. RoleID(%v)<Privilige(%v)", requestUser.RoleID, constants.Priviliges.Update), http.StatusUnauthorized, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
|
||||
return
|
||||
}
|
||||
var car models.Car
|
||||
if err := c.ShouldBindJSON(&car); err != nil {
|
||||
utils.HandleValidationError(c, err)
|
||||
return
|
||||
}
|
||||
logger.Error.Printf("updating car: %v", car)
|
||||
updatedCar, err := cr.S.Update(&car)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error updating car", http.StatusInternalServerError, errors.Responses.Fields.Car, errors.Responses.Keys.InternalServerError)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updatedCar)
|
||||
}
|
||||
|
||||
func (cr *CarController) GetAll(c *gin.Context) {
|
||||
requestUser, err := cr.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error extracting user from context in GetAll car handler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
|
||||
return
|
||||
}
|
||||
|
||||
if !requestUser.HasPrivilege(constants.Priviliges.View) {
|
||||
utils.RespondWithError(c, errors.ErrNotAuthorized, fmt.Sprintf("Not allowed to access car data. RoleID(%v)<Privilige(%v)", requestUser.RoleID, constants.Priviliges.Delete), http.StatusUnauthorized, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
cars, err := cr.S.GetAll()
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error getting cars", http.StatusInternalServerError, errors.Responses.Fields.Car, errors.Responses.Keys.InternalServerError)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"cars": cars,
|
||||
})
|
||||
}
|
||||
|
||||
func (cr *CarController) Delete(c *gin.Context) {
|
||||
type input struct {
|
||||
Car struct {
|
||||
ID uint `json:"id" binding:"required,numeric"`
|
||||
} `json:"car"`
|
||||
}
|
||||
var deleteData input
|
||||
requestUser, err := cr.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error extracting user from context in Delete car handler", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
|
||||
return
|
||||
}
|
||||
|
||||
if !requestUser.HasPrivilege(constants.Priviliges.Delete) {
|
||||
utils.RespondWithError(c, errors.ErrNotAuthorized, fmt.Sprintf("Not allowed to delete a car. RoleID(%v)<Privilige(%v)", requestUser.RoleID, constants.Priviliges.Delete), http.StatusUnauthorized, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&deleteData); err != nil {
|
||||
utils.HandleValidationError(c, err)
|
||||
return
|
||||
}
|
||||
err = cr.S.Delete(&deleteData.Car.ID)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error deleting car", http.StatusInternalServerError, errors.Responses.Fields.Car, errors.Responses.Keys.InternalServerError)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, "Car deleted")
|
||||
}
|
||||
@@ -20,13 +20,7 @@ type MembershipController struct {
|
||||
UserService services.UserServiceInterface
|
||||
}
|
||||
|
||||
type MembershipData struct {
|
||||
// APIKey string `json:"api_key"`
|
||||
Subscription models.SubscriptionModel `json:"subscription"`
|
||||
}
|
||||
|
||||
func (mc *MembershipController) RegisterSubscription(c *gin.Context) {
|
||||
var regData MembershipData
|
||||
|
||||
requestUser, err := mc.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
@@ -39,13 +33,14 @@ func (mc *MembershipController) RegisterSubscription(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(®Data); err != nil {
|
||||
var subscription models.SubscriptionModel
|
||||
if err := c.ShouldBindJSON(&subscription); err != nil {
|
||||
utils.HandleValidationError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Register Subscription
|
||||
id, err := mc.Service.RegisterSubscription(®Data.Subscription)
|
||||
id, err := mc.Service.RegisterSubscription(&subscription)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "UNIQUE constraint failed") {
|
||||
utils.RespondWithError(c, err, "Subscription already exists", http.StatusConflict, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.Duplicate)
|
||||
@@ -54,7 +49,7 @@ func (mc *MembershipController) RegisterSubscription(c *gin.Context) {
|
||||
}
|
||||
return
|
||||
}
|
||||
logger.Info.Printf("registering subscription: %+v", regData)
|
||||
logger.Info.Printf("registering subscription: %+v", subscription)
|
||||
c.JSON(http.StatusCreated, gin.H{
|
||||
"status": "success",
|
||||
"id": id,
|
||||
@@ -62,7 +57,6 @@ func (mc *MembershipController) RegisterSubscription(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (mc *MembershipController) UpdateHandler(c *gin.Context) {
|
||||
var regData MembershipData
|
||||
|
||||
requestUser, err := mc.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
@@ -75,19 +69,19 @@ func (mc *MembershipController) UpdateHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(®Data); err != nil {
|
||||
var subscription models.SubscriptionModel
|
||||
if err := c.ShouldBindJSON(&subscription); err != nil {
|
||||
utils.HandleValidationError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// update Subscription
|
||||
logger.Info.Printf("Updating subscription %v", regData.Subscription.Name)
|
||||
id, err := mc.Service.UpdateSubscription(®Data.Subscription)
|
||||
logger.Info.Printf("Updating subscription %v", subscription.Name)
|
||||
id, err := mc.Service.UpdateSubscription(&subscription)
|
||||
if err != nil {
|
||||
utils.HandleSubscriptionUpdateError(c, err)
|
||||
return
|
||||
}
|
||||
logger.Info.Printf("updating subscription: %+v", regData)
|
||||
c.JSON(http.StatusAccepted, gin.H{
|
||||
"status": "success",
|
||||
"id": id,
|
||||
@@ -96,13 +90,11 @@ func (mc *MembershipController) UpdateHandler(c *gin.Context) {
|
||||
|
||||
func (mc *MembershipController) DeleteSubscription(c *gin.Context) {
|
||||
type deleteData struct {
|
||||
Subscription struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"subscription"`
|
||||
ID uint `json:"id" binding:"required,numeric,safe_content"`
|
||||
Name string `json:"name" binding:"required,safe_content"`
|
||||
}
|
||||
|
||||
var data deleteData
|
||||
var subscription deleteData
|
||||
requestUser, err := mc.UserService.FromContext(c)
|
||||
if err != nil {
|
||||
utils.RespondWithError(c, err, "Error extracting user from context in subscription deleteSubscription", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.NoAuthToken)
|
||||
@@ -114,12 +106,12 @@ func (mc *MembershipController) DeleteSubscription(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&data); err != nil {
|
||||
if err := c.ShouldBindJSON(&subscription); err != nil {
|
||||
utils.HandleValidationError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := mc.Service.DeleteSubscription(&data.Subscription.ID, &data.Subscription.Name); err != nil {
|
||||
if err := mc.Service.DeleteSubscription(&subscription.ID, &subscription.Name); err != nil {
|
||||
utils.HandleSubscriptionDeleteError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -148,18 +148,16 @@ func (dt *DeleteSubscriptionTest) ValidateResult() error {
|
||||
return validateSubscription(dt.Assert, dt.WantDBData)
|
||||
}
|
||||
|
||||
func getBaseSubscription() MembershipData {
|
||||
return MembershipData{
|
||||
// APIKey: config.Auth.APIKEY,
|
||||
Subscription: models.SubscriptionModel{
|
||||
func getBaseSubscription() models.SubscriptionModel {
|
||||
return models.SubscriptionModel{
|
||||
Name: "Premium",
|
||||
Details: "A subscription detail",
|
||||
MonthlyFee: 12.0,
|
||||
HourlyRate: 14.0,
|
||||
},
|
||||
}
|
||||
}
|
||||
func customizeSubscription(customize func(MembershipData) MembershipData) MembershipData {
|
||||
|
||||
func customizeSubscription(customize func(models.SubscriptionModel) models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription := getBaseSubscription()
|
||||
return customize(subscription)
|
||||
}
|
||||
@@ -175,8 +173,8 @@ func getSubscriptionRegistrationData() []RegisterSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Just a Subscription"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Details = ""
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Details = ""
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -189,8 +187,8 @@ func getSubscriptionRegistrationData() []RegisterSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": ""},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = ""
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = ""
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -202,8 +200,8 @@ func getSubscriptionRegistrationData() []RegisterSubscriptionTest {
|
||||
WantResponse: http.StatusBadRequest,
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(customizeSubscription(func(sub MembershipData) MembershipData {
|
||||
sub.Subscription.MonthlyFee = -10.0
|
||||
Input: GenerateInputJSON(customizeSubscription(func(sub models.SubscriptionModel) models.SubscriptionModel {
|
||||
sub.MonthlyFee = -10.0
|
||||
return sub
|
||||
})),
|
||||
},
|
||||
@@ -215,8 +213,8 @@ func getSubscriptionRegistrationData() []RegisterSubscriptionTest {
|
||||
WantResponse: http.StatusBadRequest,
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(customizeSubscription(func(sub MembershipData) MembershipData {
|
||||
sub.Subscription.HourlyRate = -1.0
|
||||
Input: GenerateInputJSON(customizeSubscription(func(sub models.SubscriptionModel) models.SubscriptionModel {
|
||||
sub.HourlyRate = -1.0
|
||||
return sub
|
||||
})),
|
||||
},
|
||||
@@ -229,10 +227,10 @@ func getSubscriptionRegistrationData() []RegisterSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Conditions = "Some Condition"
|
||||
subscription.Subscription.IncludedPerYear = 0
|
||||
subscription.Subscription.IncludedPerMonth = 1
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Conditions = "Some Condition"
|
||||
subscription.IncludedPerYear = 0
|
||||
subscription.IncludedPerMonth = 1
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -245,10 +243,10 @@ func getSubscriptionRegistrationData() []RegisterSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Conditions = "Some Condition"
|
||||
subscription.Subscription.IncludedPerYear = 0
|
||||
subscription.Subscription.IncludedPerMonth = 1
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Conditions = "Some Condition"
|
||||
subscription.IncludedPerYear = 0
|
||||
subscription.IncludedPerMonth = 1
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -276,8 +274,8 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium", "monthly_fee": "12"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.MonthlyFee = 123.0
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.MonthlyFee = 123.0
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -290,8 +288,8 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.ID = 0
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.ID = 0
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -304,8 +302,8 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium", "hourly_rate": "14"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.HourlyRate = 3254.0
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.HourlyRate = 3254.0
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -318,8 +316,8 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium", "included_per_year": "0"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.IncludedPerYear = 9873.0
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.IncludedPerYear = 9873.0
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -332,8 +330,8 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium", "included_per_month": "1"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.IncludedPerMonth = 23415.0
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.IncludedPerMonth = 23415.0
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -346,8 +344,8 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "NonExistentSubscription"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = "NonExistentSubscription"
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = "NonExistentSubscription"
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -360,11 +358,11 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium", "details": "Altered Details"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Details = "Altered Details"
|
||||
subscription.Subscription.Conditions = "Some Condition"
|
||||
subscription.Subscription.IncludedPerYear = 0
|
||||
subscription.Subscription.IncludedPerMonth = 1
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Details = "Altered Details"
|
||||
subscription.Conditions = "Some Condition"
|
||||
subscription.IncludedPerYear = 0
|
||||
subscription.IncludedPerMonth = 1
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -377,11 +375,11 @@ func getSubscriptionUpdateData() []UpdateSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium", "details": "Altered Details"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Details = "Altered Details"
|
||||
subscription.Subscription.Conditions = "Some Condition"
|
||||
subscription.Subscription.IncludedPerYear = 0
|
||||
subscription.Subscription.IncludedPerMonth = 1
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Details = "Altered Details"
|
||||
subscription.Conditions = "Some Condition"
|
||||
subscription.IncludedPerYear = 0
|
||||
subscription.IncludedPerMonth = 1
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -404,9 +402,10 @@ func getSubscriptionDeleteData() []DeleteSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "NonExistentSubscription"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = "NonExistentSubscription"
|
||||
subscription.Subscription.ID = basicSub.ID
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = "NonExistentSubscription"
|
||||
subscription.ID = basicSub.ID
|
||||
logger.Error.Printf("subscription to delete: %#v", subscription)
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -415,13 +414,13 @@ func getSubscriptionDeleteData() []DeleteSubscriptionTest {
|
||||
req.AddCookie(AdminCookie)
|
||||
},
|
||||
Name: "Delete subscription without name should fail",
|
||||
WantResponse: http.StatusExpectationFailed,
|
||||
WantResponse: http.StatusBadRequest,
|
||||
WantDBData: map[string]interface{}{"name": ""},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = ""
|
||||
subscription.Subscription.ID = basicSub.ID
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = ""
|
||||
subscription.ID = basicSub.ID
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -434,9 +433,9 @@ func getSubscriptionDeleteData() []DeleteSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Basic"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = "Basic"
|
||||
subscription.Subscription.ID = basicSub.ID
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = "Basic"
|
||||
subscription.ID = basicSub.ID
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -449,9 +448,9 @@ func getSubscriptionDeleteData() []DeleteSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = "Premium"
|
||||
subscription.Subscription.ID = premiumSub.ID
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = "Premium"
|
||||
subscription.ID = premiumSub.ID
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
@@ -464,9 +463,9 @@ func getSubscriptionDeleteData() []DeleteSubscriptionTest {
|
||||
WantDBData: map[string]interface{}{"name": "Premium"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.Subscription.Name = "Premium"
|
||||
subscription.Subscription.ID = premiumSub.ID
|
||||
customizeSubscription(func(subscription models.SubscriptionModel) models.SubscriptionModel {
|
||||
subscription.Name = "Premium"
|
||||
subscription.ID = premiumSub.ID
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
|
||||
@@ -75,7 +75,7 @@ func (uc *UserController) GetAllUsers(c *gin.Context) {
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"users": users,
|
||||
"users": safeUsers,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -139,7 +139,6 @@ func (uc *UserController) DeleteUser(c *gin.Context) {
|
||||
type deleteData struct {
|
||||
User struct {
|
||||
ID uint `json:"id" binding:"required,numeric"`
|
||||
LastName string `json:"last_name"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
|
||||
@@ -245,12 +245,12 @@ func testLoginHandler(t *testing.T) string {
|
||||
if cookie.Name == "jwt" {
|
||||
MemberCookie = cookie
|
||||
|
||||
// tokenString := loginCookie.Value
|
||||
// _, claims, err := middlewares.ExtractContentFrom(tokenString)
|
||||
// assert.NoError(t, err, "FAiled getting cookie string")
|
||||
// jwtUserID := uint((*claims)["user_id"].(float64))
|
||||
// user, err := Uc.Service.GetUserByID(jwtUserID)
|
||||
// assert.NoError(t, err, "FAiled getting cookie string")
|
||||
tokenString := cookie.Value
|
||||
_, claims, err := middlewares.ExtractContentFrom(tokenString)
|
||||
assert.NoError(t, err, "FAiled getting cookie string")
|
||||
jwtUserID := uint((*claims)["user_id"].(float64))
|
||||
_, err = Uc.Service.FromID(&jwtUserID)
|
||||
assert.NoError(t, err, "FAiled getting cookie string")
|
||||
|
||||
// logger.Error.Printf("cookie user: %#v", user)
|
||||
err = json.Unmarshal([]byte(tt.input), &loginInput)
|
||||
@@ -1254,35 +1254,35 @@ func getTestUsers() []RegisterUserTest {
|
||||
// return user
|
||||
// })),
|
||||
// },
|
||||
// {
|
||||
// Name: "empty driverslicence number, should fail",
|
||||
// WantResponse: http.StatusBadRequest,
|
||||
// WantDBData: map[string]interface{}{"email": "john.wronglicence.doe@example.com"},
|
||||
// Assert: false,
|
||||
// Input: GenerateInputJSON(customizeInput(func(user models.User) models.User {
|
||||
// user.Email = "john.wronglicence.doe@example.com"
|
||||
// user.Licence = &models.Licence{
|
||||
// Number: "",
|
||||
// ExpirationDate: time.Now().AddDate(1, 0, 0),
|
||||
// IssuedDate: time.Now().AddDate(-1, 0, 0),
|
||||
// }
|
||||
// return user
|
||||
// })),
|
||||
// },
|
||||
// {
|
||||
// Name: "Correct Licence number, should pass",
|
||||
// WantResponse: http.StatusCreated,
|
||||
// WantDBData: map[string]interface{}{"email": "john.correctLicenceNumber@example.com"},
|
||||
// Assert: true,
|
||||
// Input: GenerateInputJSON(customizeInput(func(user models.User) models.User {
|
||||
// user.Email = "john.correctLicenceNumber@example.com"
|
||||
// user.Licence = &models.Licence{
|
||||
// Number: "B072RRE2I55",
|
||||
// ExpirationDate: time.Now().AddDate(1, 0, 0),
|
||||
// IssuedDate: time.Now().AddDate(-1, 0, 0),
|
||||
// }
|
||||
// return user
|
||||
// })),
|
||||
// },
|
||||
{
|
||||
Name: "empty driverslicence number, should fail",
|
||||
WantResponse: http.StatusBadRequest,
|
||||
WantDBData: map[string]interface{}{"email": "john.wronglicence.doe@example.com"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(customizeInput(func(user models.User) models.User {
|
||||
user.Email = "john.wronglicence.doe@example.com"
|
||||
user.Licence = &models.Licence{
|
||||
Number: "",
|
||||
ExpirationDate: time.Now().AddDate(1, 0, 0),
|
||||
IssuedDate: time.Now().AddDate(-1, 0, 0),
|
||||
}
|
||||
return user
|
||||
})),
|
||||
},
|
||||
{
|
||||
Name: "Correct Licence number, should pass",
|
||||
WantResponse: http.StatusCreated,
|
||||
WantDBData: map[string]interface{}{"email": "john.correctLicenceNumber@example.com"},
|
||||
Assert: true,
|
||||
Input: GenerateInputJSON(customizeInput(func(user models.User) models.User {
|
||||
user.Email = "john.correctLicenceNumber@example.com"
|
||||
user.Licence = &models.Licence{
|
||||
Number: "B072RRE2I55",
|
||||
ExpirationDate: time.Now().AddDate(1, 0, 0),
|
||||
IssuedDate: time.Now().AddDate(-1, 0, 0),
|
||||
}
|
||||
return user
|
||||
})),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ func Open(dbPath string, adminMail string) (*gorm.DB, error) {
|
||||
&models.Verification{},
|
||||
&models.Licence{},
|
||||
&models.Category{},
|
||||
&models.Insurance{},
|
||||
&models.Car{},
|
||||
&models.Location{},
|
||||
&models.Damage{},
|
||||
&models.BankAccount{}); err != nil {
|
||||
logger.Error.Fatalf("Couldn't create database: %v", err)
|
||||
return nil, err
|
||||
|
||||
13
go-backend/internal/models/Insurance.go
Normal file
13
go-backend/internal/models/Insurance.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type Insurance struct {
|
||||
ID uint `gorm:"primary_key" json:"id"`
|
||||
OwnerID uint `gorm:"not null" json:"owner_id" binding:"numeric"`
|
||||
Company string `json:"company" binding:"safe_content"`
|
||||
Reference string `json:"reference" binding:"safe_content"`
|
||||
Notes string `json:"notes" binding:"safe_content"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
}
|
||||
@@ -3,13 +3,13 @@ package models
|
||||
import "time"
|
||||
|
||||
type BankAccount struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
MandateDateSigned time.Time `gorm:"not null" json:"mandate_date_signed"`
|
||||
Bank string `json:"bank_name" binding:"safe_content"`
|
||||
AccountHolderName string `json:"account_holder_name" binding:"safe_content"`
|
||||
IBAN string `json:"iban"`
|
||||
BIC string `json:"bic"`
|
||||
MandateReference string `gorm:"not null" json:"mandate_reference"`
|
||||
ID uint `gorm:"primaryKey"`
|
||||
IBAN string `json:"iban" binding:"safe_content"`
|
||||
BIC string `json:"bic" binding:"safe_content"`
|
||||
MandateReference string `gorm:"not null" json:"mandate_reference" binding:"safe_content"`
|
||||
}
|
||||
|
||||
133
go-backend/internal/models/car.go
Normal file
133
go-backend/internal/models/car.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/errors"
|
||||
"GoMembership/pkg/logger"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Car struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
Status uint `json:"status"`
|
||||
Name string `json:"name"`
|
||||
Brand string `gorm:"not null" json:"brand"`
|
||||
Model string `gorm:"not null" json:"model"`
|
||||
Color string `gorm:"not null" json:"color"`
|
||||
LicencePlate string `gorm:"not null,unique" json:"licence_plate"`
|
||||
Price float32 `json:"price"`
|
||||
Rate float32 `json:"rate"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
Location Location `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"location"`
|
||||
LocationID uint
|
||||
Damages *[]Damage `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"damages"`
|
||||
Insurances *[]Insurance `gorm:"foreignkey:OwnerID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"insurance"`
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
type Location struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
Latitude float32 `json:"latitude"`
|
||||
Longitude float32 `json:"longitude"`
|
||||
}
|
||||
|
||||
type Damage struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CarID uint `json:"car_id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
Opponent *User `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"opponent"`
|
||||
OpponentID uint
|
||||
Insurance *Insurance `gorm:"foreignkey:OwnerID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"insurance"`
|
||||
InsuranceID uint
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
func (c *Car) Create(db *gorm.DB) error {
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// Create the base User record (omit associations to handle them separately)
|
||||
if err := tx.Create(c).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Replace associated Categories (assumes Categories already exist)
|
||||
if c.Insurances != nil {
|
||||
if err := tx.Model(c).Association("Insurances").Replace(c.Insurances); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
logger.Info.Printf("car created: %#v", c)
|
||||
// Preload all associations to return the fully populated User
|
||||
return tx.
|
||||
Preload("Insurances").
|
||||
First(c, c.ID).Error // Refresh the user object with all associations
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Car) Update(db *gorm.DB) error {
|
||||
|
||||
err := db.Transaction(func(tx *gorm.DB) error {
|
||||
// Check if the user exists in the database
|
||||
var existingCar Car
|
||||
|
||||
logger.Info.Printf("updating car: %#v", c)
|
||||
if err := tx.
|
||||
Preload("Insurances").
|
||||
First(&existingCar, c.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
result := tx.Session(&gorm.Session{FullSaveAssociations: true}).Updates(c)
|
||||
if result.Error != nil {
|
||||
logger.Error.Printf("car update error: %#v", result.Error)
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return errors.ErrNoRowsAffected
|
||||
}
|
||||
|
||||
if c.Insurances != nil {
|
||||
if err := tx.Save(*c.Insurances).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.
|
||||
Preload("Insurances").
|
||||
First(&c, c.ID).Error
|
||||
}
|
||||
|
||||
func (c *Car) Delete(db *gorm.DB) error {
|
||||
return db.Delete(&c).Error
|
||||
}
|
||||
|
||||
func GetAllCars(db *gorm.DB) ([]Car, error) {
|
||||
var cars []Car
|
||||
if err := db.Find(&cars).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cars, nil
|
||||
}
|
||||
|
||||
func (c *Car) FromID(db *gorm.DB, id uint) error {
|
||||
var car Car
|
||||
if err := db.Preload("Insurances").First(&car, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
*c = car
|
||||
return nil
|
||||
}
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
)
|
||||
|
||||
type SubscriptionModel struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string `gorm:"unique" json:"name" binding:"required"`
|
||||
Details string `json:"details"`
|
||||
Conditions string `json:"conditions"`
|
||||
RequiredMembershipField string `json:"required_membership_field"`
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
Name string `gorm:"uniqueIndex:idx_subscriptions_name" json:"name" binding:"required,safe_content"`
|
||||
Details string `json:"details" binding:"safe_content"`
|
||||
Conditions string `json:"conditions" binding:"safe_content"`
|
||||
RequiredMembershipField string `json:"required_membership_field" binding:"safe_content"`
|
||||
MonthlyFee float32 `json:"monthly_fee"`
|
||||
HourlyRate float32 `json:"hourly_rate"`
|
||||
IncludedPerYear int16 `json:"included_hours_per_year"`
|
||||
|
||||
@@ -21,26 +21,26 @@ type User struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time `gorm:"index"`
|
||||
DeletedAt *time.Time
|
||||
DateOfBirth time.Time `gorm:"not null" json:"dateofbirth" binding:"required_unless=RoleID 0,safe_content"`
|
||||
Company string `json:"company" binding:"omitempty,omitnil,safe_content"`
|
||||
Phone string `json:"phone" binding:"omitempty,omitnil,safe_content"`
|
||||
Notes string `json:"notes" binding:"safe_content"`
|
||||
FirstName string `gorm:"not null" json:"first_name" binding:"required,safe_content"`
|
||||
Password string `json:"password" binding:"safe_content"`
|
||||
Email string `gorm:"unique;not null" json:"email" binding:"required,email,safe_content"`
|
||||
Email string `gorm:"uniqueIndex:idx_users_email,not null" json:"email" binding:"required,email,safe_content"`
|
||||
LastName string `gorm:"not null" json:"last_name" binding:"required,safe_content"`
|
||||
ProfilePicture string `json:"profile_picture" binding:"omitempty,omitnil,image,safe_content"`
|
||||
Address string `gorm:"not null" json:"address" binding:"required,safe_content"`
|
||||
ZipCode string `gorm:"not null" json:"zip_code" binding:"required,alphanum,safe_content"`
|
||||
City string `form:"not null" json:"city" binding:"required,alphaunicode,safe_content"`
|
||||
Consents []Consent `gorm:"constraint:OnUpdate:CASCADE"`
|
||||
BankAccount BankAccount `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"bank_account"`
|
||||
BankAccount BankAccount `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"bank_account"`
|
||||
BankAccountID uint
|
||||
Verifications *[]Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
|
||||
Membership Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"membership"`
|
||||
Verifications *[]Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||
Membership Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"membership"`
|
||||
MembershipID uint
|
||||
Licence *Licence `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"licence"`
|
||||
Licence *Licence `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"licence"`
|
||||
LicenceID uint
|
||||
PaymentStatus int8 `json:"payment_status"`
|
||||
Status int8 `json:"status"`
|
||||
|
||||
69
go-backend/internal/repositories/car_repository.go
Normal file
69
go-backend/internal/repositories/car_repository.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"GoMembership/internal/database"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/pkg/errors"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// CarRepository interface defines the CRUD operations
|
||||
type CarRepositoryInterface interface {
|
||||
Create(car *models.Car) (*models.Car, error)
|
||||
GetByID(id uint) (*models.Car, error)
|
||||
GetAll() ([]models.Car, error)
|
||||
Update(car *models.Car) (*models.Car, error)
|
||||
Delete(id uint) error
|
||||
}
|
||||
|
||||
type CarRepository struct{}
|
||||
|
||||
// Create a new car
|
||||
func (r *CarRepository) Create(car *models.Car) (*models.Car, error) {
|
||||
if err := database.DB.Create(car).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return car, nil
|
||||
}
|
||||
|
||||
// GetByID fetches a car by its ID
|
||||
func (r *CarRepository) GetByID(id uint) (*models.Car, error) {
|
||||
var car models.Car
|
||||
if err := database.DB.Where("id = ?", id).First(&car).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &car, nil
|
||||
}
|
||||
|
||||
// GetAll retrieves all cars
|
||||
func (r *CarRepository) GetAll() ([]models.Car, error) {
|
||||
var cars []models.Car
|
||||
if err := database.DB.Find(&cars).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cars, nil
|
||||
}
|
||||
|
||||
// Update an existing car
|
||||
func (r *CarRepository) Update(car *models.Car) (*models.Car, error) {
|
||||
if err := database.DB.Save(car).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return car, nil
|
||||
}
|
||||
|
||||
// Delete a car (soft delete)
|
||||
func (r *CarRepository) Delete(id uint) error {
|
||||
result := database.DB.Delete(&models.Car{}, id)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterRoutes(router *gin.Engine, userController *controllers.UserController, membershipcontroller *controllers.MembershipController, contactController *controllers.ContactController, licenceController *controllers.LicenceController) {
|
||||
func RegisterRoutes(router *gin.Engine, userController *controllers.UserController, membershipcontroller *controllers.MembershipController, contactController *controllers.ContactController, licenceController *controllers.LicenceController, carController *controllers.CarController) {
|
||||
router.GET("/api/users/verify/:id", userController.VerifyMailHandler)
|
||||
router.POST("/api/users/register", userController.RegisterUser)
|
||||
router.POST("/api/users/contact", contactController.RelayContactRequest)
|
||||
@@ -19,6 +19,10 @@ func RegisterRoutes(router *gin.Engine, userController *controllers.UserControll
|
||||
userRouter := router.Group("/api/auth")
|
||||
userRouter.Use(middlewares.AuthMiddleware())
|
||||
{
|
||||
userRouter.GET("/cars", carController.GetAll)
|
||||
userRouter.PUT("/cars", carController.Update)
|
||||
userRouter.POST("/cars", carController.Create)
|
||||
userRouter.DELETE("/cars", carController.Delete)
|
||||
userRouter.GET("/users/current", userController.CurrentUserHandler)
|
||||
userRouter.POST("/logout", userController.LogoutHandler)
|
||||
userRouter.PUT("/users", userController.UpdateHandler)
|
||||
|
||||
@@ -48,6 +48,8 @@ func Run(db *gorm.DB) {
|
||||
membershipController := &controllers.MembershipController{Service: membershipService, UserService: userService}
|
||||
licenceController := &controllers.LicenceController{Service: licenceService}
|
||||
contactController := &controllers.ContactController{EmailService: emailService}
|
||||
carService := &services.CarService{DB: db}
|
||||
carController := &controllers.CarController{S: carService, UserService: userService}
|
||||
|
||||
router := gin.Default()
|
||||
// gin.SetMode(gin.ReleaseMode)
|
||||
@@ -63,7 +65,7 @@ func Run(db *gorm.DB) {
|
||||
limiter := middlewares.NewIPRateLimiter(config.Security.Ratelimits.Limit, config.Security.Ratelimits.Burst)
|
||||
router.Use(middlewares.RateLimitMiddleware(limiter))
|
||||
|
||||
routes.RegisterRoutes(router, userController, membershipController, contactController, licenceController)
|
||||
routes.RegisterRoutes(router, userController, membershipController, contactController, licenceController, carController)
|
||||
validation.SetupValidators(db)
|
||||
|
||||
logger.Info.Println("Starting server on :8080")
|
||||
|
||||
67
go-backend/internal/services/car_service.go
Normal file
67
go-backend/internal/services/car_service.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"GoMembership/internal/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CarServiceInterface interface {
|
||||
Create(car *models.Car) (*models.Car, error)
|
||||
Update(car *models.Car) (*models.Car, error)
|
||||
Delete(carID *uint) error
|
||||
FromID(id uint) (*models.Car, error)
|
||||
GetAll() (*[]models.Car, error)
|
||||
}
|
||||
|
||||
type CarService struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
// Create a new car
|
||||
func (s *CarService) Create(car *models.Car) (*models.Car, error) {
|
||||
|
||||
err := car.Create(s.DB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return car, nil
|
||||
}
|
||||
|
||||
// Update an existing car
|
||||
func (s *CarService) Update(car *models.Car) (*models.Car, error) {
|
||||
err := car.Update(s.DB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return car, nil
|
||||
}
|
||||
|
||||
// Delete a car (soft delete)
|
||||
func (s *CarService) Delete(carID *uint) error {
|
||||
var car models.Car
|
||||
err := car.FromID(s.DB, *carID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return car.Delete(s.DB)
|
||||
}
|
||||
|
||||
// GetByID fetches a car by its ID
|
||||
func (s *CarService) FromID(id uint) (*models.Car, error) {
|
||||
car := &models.Car{}
|
||||
err := car.FromID(s.DB, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return car, nil
|
||||
}
|
||||
|
||||
// GetAll retrieves all cars
|
||||
func (s *CarService) GetAll() (*[]models.Car, error) {
|
||||
var cars []models.Car
|
||||
if err := s.DB.Find(&cars).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cars, nil
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package validation
|
||||
import (
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/repositories"
|
||||
"GoMembership/pkg/logger"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
@@ -14,8 +15,8 @@ func ValidateSubscription(sl validator.StructLevel) {
|
||||
if subscription.Name == "" {
|
||||
sl.ReportError(subscription.Name, "Name", "name", "required", "")
|
||||
}
|
||||
|
||||
if sl.Parent().Type().Name() == "MembershipData" {
|
||||
logger.Error.Printf("parent.type.name: %#v", sl.Parent().Type().Name())
|
||||
if sl.Parent().Type().Name() == "" {
|
||||
// This is modifying a subscription directly
|
||||
if subscription.Details == "" {
|
||||
sl.ReportError(subscription.Details, "Details", "details", "required", "")
|
||||
|
||||
@@ -2,36 +2,6 @@ package errors
|
||||
|
||||
import "errors"
|
||||
|
||||
type ValidationKeys struct {
|
||||
Invalid string
|
||||
InternalServerError string
|
||||
InvalidJson string
|
||||
Unauthorized string
|
||||
InvalidSubscriptionModel string
|
||||
UserNotFoundWrongPassword string
|
||||
JwtGenerationFailed string
|
||||
Duplicate string
|
||||
InvalidUserID string
|
||||
PasswordAlreadyChanged string
|
||||
UserDisabled string
|
||||
NoAuthToken string
|
||||
NotFound string
|
||||
InUse string
|
||||
UndeliveredVerificationMail string
|
||||
UserAlreadyVerified string
|
||||
}
|
||||
|
||||
type ValidationFields struct {
|
||||
General string
|
||||
ParentMemberShipID string
|
||||
SubscriptionModel string
|
||||
Login string
|
||||
Email string
|
||||
User string
|
||||
Licences string
|
||||
Verification string
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("not found")
|
||||
ErrUserNotFound = errors.New("user not found")
|
||||
@@ -56,6 +26,37 @@ var (
|
||||
ErrInvalidSubscriptionData = errors.New("Provided subscription data is invalid. Immutable fields where changed.")
|
||||
)
|
||||
|
||||
type ValidationKeys struct {
|
||||
Invalid string
|
||||
InternalServerError string
|
||||
InvalidJSON string
|
||||
InvalidUserID string
|
||||
InvalidSubscriptionModel string
|
||||
Unauthorized string
|
||||
UserNotFoundWrongPassword string
|
||||
JwtGenerationFailed string
|
||||
Duplicate string
|
||||
UserDisabled string
|
||||
PasswordAlreadyChanged string
|
||||
NoAuthToken string
|
||||
NotFound string
|
||||
InUse string
|
||||
UndeliveredVerificationMail string
|
||||
UserAlreadyVerified string
|
||||
}
|
||||
|
||||
type ValidationFields struct {
|
||||
General string
|
||||
ParentMembershipID string
|
||||
SubscriptionModel string
|
||||
Login string
|
||||
Email string
|
||||
User string
|
||||
Licences string
|
||||
Verification string
|
||||
Car string
|
||||
}
|
||||
|
||||
var Responses = struct {
|
||||
Keys ValidationKeys
|
||||
Fields ValidationFields
|
||||
@@ -63,7 +64,9 @@ var Responses = struct {
|
||||
Keys: ValidationKeys{
|
||||
Invalid: "server.validation.invalid",
|
||||
InternalServerError: "server.error.internal_server_error",
|
||||
InvalidJson: "server.error.invalid_json",
|
||||
InvalidJSON: "server.error.invalid_json",
|
||||
InvalidUserID: "server.validation.invalid_user_id",
|
||||
InvalidSubscriptionModel: "server.validation.invalid_subscription_model",
|
||||
Unauthorized: "server.error.unauthorized",
|
||||
UserNotFoundWrongPassword: "server.validation.user_not_found_or_wrong_password",
|
||||
JwtGenerationFailed: "server.error.jwt_generation_failed",
|
||||
@@ -78,13 +81,14 @@ var Responses = struct {
|
||||
},
|
||||
Fields: ValidationFields{
|
||||
General: "server.general",
|
||||
ParentMemberShipID: "parent_membership_id",
|
||||
ParentMembershipID: "parent_membership_id",
|
||||
SubscriptionModel: "subscription_model",
|
||||
Login: "user.login",
|
||||
Email: "user.email",
|
||||
User: "user.user",
|
||||
Licences: "licence",
|
||||
Verification: "verification",
|
||||
Car: "car",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user