Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a023c97618 | |||
| 67c475f14c | |||
| be5be81cbd | |||
| bc75334590 | |||
| 7fdadf4b0b | |||
| 97198efb1c | |||
| 2d0bce143a | |||
| 524e517066 | |||
| d07f18d380 | |||
| f32bb49972 | |||
| 8290f77889 | |||
| ce8145a42e | |||
| 3064235a80 |
@@ -3,7 +3,7 @@ FROM node:lts AS buildfront
|
|||||||
COPY front .
|
COPY front .
|
||||||
RUN npm install && npm run build
|
RUN npm install && npm run build
|
||||||
|
|
||||||
FROM golang:1.25 AS build
|
FROM golang:1.26 AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY --from=buildfront ./dist front/dist
|
COPY --from=buildfront ./dist front/dist
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Or with a volume, for example if you created a volume named `bibliomane_data`:
|
|||||||
|
|
||||||
`--add-user` or `-a` can be used to create an account on startup. It requires a string following htpasswd format `[username]:[bcrypt hashed password]`.
|
`--add-user` or `-a` can be used to create an account on startup. It requires a string following htpasswd format `[username]:[bcrypt hashed password]`.
|
||||||
|
|
||||||
The password can be generated using `htpasswd -nB [username]`.
|
The password can be generated using `htpasswd -nBC10 [username]`.
|
||||||
|
|
||||||
For example, to create an user account `demo`:
|
For example, to create an user account `demo`:
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW'
|
|||||||
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'Le petit bleu de la côte Ouest',(SELECT id FROM authors WHERE name = 'Jean-Patrick Manchette'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'le-petit-bleu-de-la-cote-ouest.jpg'));
|
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'Le petit bleu de la côte Ouest',(SELECT id FROM authors WHERE name = 'Jean-Patrick Manchette'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'le-petit-bleu-de-la-cote-ouest.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, want_read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Le petit bleu de la côte Ouest'), true,0);
|
INSERT INTO user_books(created_at, user_id, book_id, want_read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Le petit bleu de la côte Ouest'), true,0);
|
||||||
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'D''un château l''autre',(SELECT id FROM authors WHERE name = 'Louis-Ferdinand Céline'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'dunchateaulautre.jpg'));
|
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'D''un château l''autre',(SELECT id FROM authors WHERE name = 'Louis-Ferdinand Céline'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'dunchateaulautre.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'D''un château l''autre'), true,10);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating, review) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'D''un château l''autre'), true,10, "Lorem ipsum dolor sit amet, consectetur adipisci elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
|
||||||
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'Les dieux ont soif',(SELECT id FROM authors WHERE name = 'Anatole France'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lesdieuxontsoif.jpg'));
|
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'Les dieux ont soif',(SELECT id FROM authors WHERE name = 'Anatole France'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lesdieuxontsoif.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, start_read_date, end_read_date, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Les dieux ont soif'), true,'2026-01-30 00:00:00+00:00','2026-02-13 00:00:00+00:00',7);
|
INSERT INTO user_books(created_at, user_id, book_id, read, start_read_date, end_read_date, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Les dieux ont soif'), true,'2026-01-30 00:00:00+00:00','2026-02-13 00:00:00+00:00',7);
|
||||||
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'Rigodon',(SELECT id FROM authors WHERE name = 'Louis-Ferdinand Céline'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'rigodon.jpg'));
|
INSERT INTO books(created_at, title, author_id, added_by_id, cover_id) VALUES ('NOW', 'Rigodon',(SELECT id FROM authors WHERE name = 'Louis-Ferdinand Céline'), (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'rigodon.jpg'));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bibliomane",
|
"name": "bibliomane",
|
||||||
"version": "0.3.0",
|
"version": "0.4.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -47,13 +47,8 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<RouterLink
|
<RouterLink to="/" class="navbar-item" :title="'bibliomane v' + appVersion">
|
||||||
to="/"
|
<img class="ml-3" src="/image/logo.svg" />
|
||||||
class="navbar-item"
|
|
||||||
:title="'bibliomane v' + appVersion"
|
|
||||||
activeClass="is-active"
|
|
||||||
>
|
|
||||||
<img src="/image/logo.svg" />
|
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<div class="navbar-item is-hidden-desktop">
|
<div class="navbar-item is-hidden-desktop">
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import { ref, computed } from 'vue'
|
|||||||
import {
|
import {
|
||||||
getBook,
|
getBook,
|
||||||
getImagePathOrDefault,
|
getImagePathOrDefault,
|
||||||
putReadBook,
|
putUpdateBook,
|
||||||
putWantReadBook,
|
|
||||||
putRateBook,
|
|
||||||
putStartReadDate,
|
putStartReadDate,
|
||||||
putStartReadDateUnset,
|
putStartReadDateUnset,
|
||||||
putEndReadDate,
|
putEndReadDate,
|
||||||
@@ -15,6 +13,7 @@ import {
|
|||||||
import { useRouter, onBeforeRouteUpdate } from 'vue-router'
|
import { useRouter, onBeforeRouteUpdate } from 'vue-router'
|
||||||
import { VRating } from 'vuetify/components/VRating'
|
import { VRating } from 'vuetify/components/VRating'
|
||||||
import BookFormIcons from './BookFormIcons.vue'
|
import BookFormIcons from './BookFormIcons.vue'
|
||||||
|
import ReviewWidget from './ReviewWidget.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -37,7 +36,12 @@ function onRatingUpdate(rating) {
|
|||||||
data.value.read = true
|
data.value.read = true
|
||||||
data.value.wantread = false
|
data.value.wantread = false
|
||||||
}
|
}
|
||||||
putRateBook(props.id, { rating: data.value.rating })
|
putUpdateBook(props.id, { rating: data.value.rating })
|
||||||
|
}
|
||||||
|
|
||||||
|
function onReviewUpdate(review) {
|
||||||
|
data.value.review = review
|
||||||
|
putUpdateBook(props.id, { review: data.value.review })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onReadIconClick() {
|
async function onReadIconClick() {
|
||||||
@@ -53,7 +57,7 @@ async function onReadIconClick() {
|
|||||||
|
|
||||||
function onWantReadIconClick() {
|
function onWantReadIconClick() {
|
||||||
data.value.wantread = !data.value.wantread
|
data.value.wantread = !data.value.wantread
|
||||||
putWantReadBook(props.id, { wantread: data.value.wantread })
|
putUpdateBook(props.id, { wantread: data.value.wantread })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onStartReadIconClick() {
|
async function onStartReadIconClick() {
|
||||||
@@ -100,17 +104,6 @@ function goToAuthor() {
|
|||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img v-bind:src="imagePathOrDefault" v-bind:alt="data.title" />
|
<img v-bind:src="imagePathOrDefault" v-bind:alt="data.title" />
|
||||||
</figure>
|
</figure>
|
||||||
<VRating
|
|
||||||
half-increments
|
|
||||||
hover
|
|
||||||
:length="5"
|
|
||||||
size="x-large"
|
|
||||||
density="compact"
|
|
||||||
:model-value="data.rating / 2"
|
|
||||||
@update:modelValue="onRatingUpdate"
|
|
||||||
active-color="bulma-body-color"
|
|
||||||
class="centered"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h3 class="title">{{ data.title }}</h3>
|
<h3 class="title">{{ data.title }}</h3>
|
||||||
@@ -119,6 +112,12 @@ function goToAuthor() {
|
|||||||
<div class="my-5" v-if="data.isbn">ISBN: {{ data.isbn }}</div>
|
<div class="my-5" v-if="data.isbn">ISBN: {{ data.isbn }}</div>
|
||||||
<div class="my-5" v-if="data.inventaireid">Inventaire ID: {{ data.inventaireid }}</div>
|
<div class="my-5" v-if="data.inventaireid">Inventaire ID: {{ data.inventaireid }}</div>
|
||||||
<div class="my-5" v-if="data.openlibraryid">OLID: {{ data.openlibraryid }}</div>
|
<div class="my-5" v-if="data.openlibraryid">OLID: {{ data.openlibraryid }}</div>
|
||||||
|
<ReviewWidget
|
||||||
|
:reviewtext="data.review"
|
||||||
|
:rating="data.rating"
|
||||||
|
@on-review-update="onReviewUpdate"
|
||||||
|
@on-rating-update="onRatingUpdate"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<BookFormIcons
|
<BookFormIcons
|
||||||
@@ -141,12 +140,6 @@ img {
|
|||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.centered {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
.left-panel {
|
.left-panel {
|
||||||
margin-left: 3rem;
|
margin-left: 3rem;
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ async function onStartReadIconClick() {
|
|||||||
>
|
>
|
||||||
<BigIcon
|
<BigIcon
|
||||||
icon="BIconBook"
|
icon="BIconBook"
|
||||||
:legend="$t('bookform.wantread')"
|
:legend="$t('bookform.startread')"
|
||||||
:is-set="isStartReadExpanded()"
|
:is-set="isStartReadExpanded()"
|
||||||
@click="onStartReadIconClick"
|
@click="onStartReadIconClick"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -39,4 +39,13 @@ const today = new Date().toISOString().slice(0, 10)
|
|||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.datelabel {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.datepicker {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
134
front/src/ReviewWidget.vue
Normal file
134
front/src/ReviewWidget.vue
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { VRating } from 'vuetify/components/VRating'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
rating: Number,
|
||||||
|
reviewtext: String,
|
||||||
|
})
|
||||||
|
const isTextareaExpanded = ref(false)
|
||||||
|
const isTextareaTransitionEnabled = ref(true)
|
||||||
|
|
||||||
|
defineEmits('onRatingUpdate', 'onReviewUpdate')
|
||||||
|
|
||||||
|
function computeTextareaClass() {
|
||||||
|
let classAttr =
|
||||||
|
isTextareaExpanded && isTextareaExpanded.value ? 'textarea-expanded' : 'textarea-normal'
|
||||||
|
if (isTextareaTransitionEnabled && isTextareaTransitionEnabled.value) {
|
||||||
|
classAttr += ' transition-height'
|
||||||
|
}
|
||||||
|
return classAttr
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTextAreaFocus() {
|
||||||
|
isTextareaExpanded.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
isTextareaTransitionEnabled.value = false
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="maincontainer py-5">
|
||||||
|
<div class="widget-header mb-5 full-width">
|
||||||
|
<div class="widget-title ml-3">
|
||||||
|
<h2>{{ $t('review.title') }}</h2>
|
||||||
|
<span class="ml-3">
|
||||||
|
<b-icon-pen />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<VRating
|
||||||
|
half-increments
|
||||||
|
hover
|
||||||
|
:length="5"
|
||||||
|
size="x-large"
|
||||||
|
density="compact"
|
||||||
|
:model-value="rating / 2"
|
||||||
|
@update:modelValue="(r) => $emit('onRatingUpdate', r)"
|
||||||
|
active-color="bulma-body-color"
|
||||||
|
class="widget-rating centered"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="full-width centered">
|
||||||
|
<textarea
|
||||||
|
:placeholder="$t('review.textplaceholder')"
|
||||||
|
class="widget-textarea mx-4"
|
||||||
|
@change="(e) => $emit('onReviewUpdate', e.target.value)"
|
||||||
|
@focus="onTextAreaFocus"
|
||||||
|
:class="computeTextareaClass()"
|
||||||
|
>{{ reviewtext }}</textarea
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.maincontainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
border: solid;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-header {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-title {
|
||||||
|
flex: 2;
|
||||||
|
font-size: 2em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-title h2 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-rating {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-textarea {
|
||||||
|
color: var(--bulma-body-color);
|
||||||
|
background-color: var(--bulma-text-20);
|
||||||
|
width: 95%;
|
||||||
|
border-radius: 30px;
|
||||||
|
border: none;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea-normal {
|
||||||
|
height: 80px;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea-expanded {
|
||||||
|
height: 350px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-height {
|
||||||
|
transition: height 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.widget-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.widget-title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -99,35 +99,31 @@ export async function postImportBook(id, language) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function putReadBook(bookId) {
|
export async function putReadBook(bookId) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/read', { read: true }, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, { read: true }, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putUnreadBook(bookId) {
|
export async function putUnreadBook(bookId) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/read', { read: false }, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, { read: false }, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putEndReadDate(bookId, enddate) {
|
export async function putEndReadDate(bookId, enddate) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/read', { read: true, endDate: enddate }, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, { read: true, endDate: enddate }, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putEndReadDateUnset(bookId) {
|
export async function putEndReadDateUnset(bookId) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/read', { read: true, endDate: 'null' }, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, { read: true, endDate: 'null' }, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putStartReadDateUnset(bookId) {
|
export async function putStartReadDateUnset(bookId) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/startread', { startDate: 'null' }, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, { startDate: 'null' }, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putStartReadDate(bookId, startdate) {
|
export async function putStartReadDate(bookId, startdate) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/startread', { startDate: startdate }, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, { startDate: startdate }, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putWantReadBook(bookId, payload) {
|
export async function putUpdateBook(bookId, payload) {
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/wantread', payload, 'PUT')
|
return genericPayloadCall('/ws/book/' + bookId, payload, 'PUT')
|
||||||
}
|
|
||||||
|
|
||||||
export async function putRateBook(bookId, payload) {
|
|
||||||
return genericPayloadCall('/ws/book/' + bookId + '/rate', payload, 'PUT')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postLogin(user) {
|
export function postLogin(user) {
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"bookform": {
|
"bookform": {
|
||||||
"error": "Error when loading book: {error}",
|
"error": "Error when loading book: {error}",
|
||||||
|
"reviewbtn": "My review",
|
||||||
"read": "Read",
|
"read": "Read",
|
||||||
"startread": "Started",
|
"startread": "Started",
|
||||||
"wantread": "Interested"
|
"wantread": "Interested"
|
||||||
@@ -80,5 +81,9 @@
|
|||||||
"releasedate": "Release date:",
|
"releasedate": "Release date:",
|
||||||
"publisher": "Publisher:",
|
"publisher": "Publisher:",
|
||||||
"importing": "Importing..."
|
"importing": "Importing..."
|
||||||
|
},
|
||||||
|
"review": {
|
||||||
|
"title": "My review",
|
||||||
|
"textplaceholder": "Write my review..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"bookform": {
|
"bookform": {
|
||||||
"error": "Erreur pendant le chargement du livre: {error}",
|
"error": "Erreur pendant le chargement du livre: {error}",
|
||||||
|
"reviewbtn": "Ma critique",
|
||||||
"read": "Lu",
|
"read": "Lu",
|
||||||
"startread": "Commencé",
|
"startread": "Commencé",
|
||||||
"wantread": "À lire"
|
"wantread": "À lire"
|
||||||
@@ -80,5 +81,9 @@
|
|||||||
"releasedate": "Date de publication : ",
|
"releasedate": "Date de publication : ",
|
||||||
"publisher": "Maison d'édition : ",
|
"publisher": "Maison d'édition : ",
|
||||||
"importing": "Import en cours..."
|
"importing": "Import en cours..."
|
||||||
|
},
|
||||||
|
"review": {
|
||||||
|
"title": "Ma critique",
|
||||||
|
"textplaceholder": "Écrire ma critique..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
.clickable {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func TestGetBook_Ok(t *testing.T) {
|
|||||||
Rating: 10,
|
Rating: 10,
|
||||||
Read: true,
|
Read: true,
|
||||||
CoverPath: "/static/bookcover/dunchateaulautre.jpg",
|
CoverPath: "/static/bookcover/dunchateaulautre.jpg",
|
||||||
|
Review: "Lorem ipsum dolor sit amet, consectetur adipisci elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||||
}, book)
|
}, book)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
package apitest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/testutils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_UpdateRating(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": 5
|
|
||||||
}`
|
|
||||||
bookId := "17"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, 5, book.Rating)
|
|
||||||
assert.Equal(t, true, book.Read)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_RateNewBookMakeItRead(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": 7
|
|
||||||
}`
|
|
||||||
bookId := "18"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, 7, book.Rating)
|
|
||||||
assert.Equal(t, true, book.Read)
|
|
||||||
assert.Equal(t, false, book.WantRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_RateWantedBook(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": 6
|
|
||||||
}`
|
|
||||||
bookId := "2"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, 6, book.Rating)
|
|
||||||
assert.Equal(t, true, book.Read)
|
|
||||||
assert.Equal(t, false, book.WantRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_RatingTypeWrong(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": "bad"
|
|
||||||
}`
|
|
||||||
bookId := "18"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_RatingMin(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": -3
|
|
||||||
}`
|
|
||||||
bookId := "18"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_RatingMax(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": 15
|
|
||||||
}`
|
|
||||||
bookId := "18"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutRatingUserBooksHandler_BadBookId(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"rating": 15
|
|
||||||
}`
|
|
||||||
bookId := "18574"
|
|
||||||
testPutRateUserBooks(t, payload, bookId, http.StatusNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPutRateUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
|
||||||
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/ws/book/"+bookId+"/rate")
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package apitest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/testutils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPutReadUserBooks_NewReadOk(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"read": true
|
|
||||||
}`
|
|
||||||
bookId := "21"
|
|
||||||
testPutReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, true, book.Read)
|
|
||||||
assert.Equal(t, false, book.WantRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutReadUserBooks_NewReadDateOk(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"read": true,
|
|
||||||
"endDate": "2025-10-20"
|
|
||||||
}`
|
|
||||||
bookId := "9"
|
|
||||||
testPutReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, true, book.Read)
|
|
||||||
assert.Equal(t, "2025-10-20", book.EndReadDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutReadUserBooks_UnsetEndDate(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"read": true,
|
|
||||||
"endDate": "null"
|
|
||||||
}`
|
|
||||||
bookId := "9"
|
|
||||||
testPutReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, true, book.Read)
|
|
||||||
assert.Equal(t, "", book.EndReadDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutReadUserBooks_UnsetReadOk(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"read": false
|
|
||||||
}`
|
|
||||||
bookId := "9"
|
|
||||||
testPutReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, false, book.Read)
|
|
||||||
assert.Equal(t, "", book.EndReadDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPutReadUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
|
||||||
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/ws/book/"+bookId+"/read")
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package apitest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/testutils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPutStartReadUserBooks_NoDate(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"date": "2025-11-19"
|
|
||||||
}`
|
|
||||||
bookId := "6"
|
|
||||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutStartReadUserBooks_WrongDateFormat(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"startDate": "19/11/2025"
|
|
||||||
}`
|
|
||||||
bookId := "6"
|
|
||||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutStartReadUserBooks_NewReadOk(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"startDate": "2025-11-19"
|
|
||||||
}`
|
|
||||||
bookId := "6"
|
|
||||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, "2025-11-19", book.StartReadDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutStartReadUserBooks_Unset(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"startDate": "null"
|
|
||||||
}`
|
|
||||||
bookId := "6"
|
|
||||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, "", book.StartReadDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPutStartReadUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
|
||||||
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/ws/book/"+bookId+"/startread")
|
|
||||||
}
|
|
||||||
190
internal/apitest/put_userbook_test.go
Normal file
190
internal/apitest/put_userbook_test.go
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
package apitest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.artlef.fr/bibliomane/internal/testutils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_UpdateRating(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": 5
|
||||||
|
}`
|
||||||
|
bookId := "17"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, 5, book.Rating)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_RateNewBookMakeItRead(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": 7
|
||||||
|
}`
|
||||||
|
bookId := "18"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, 7, book.Rating)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_RateWantedBook(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": 6
|
||||||
|
}`
|
||||||
|
bookId := "2"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, 6, book.Rating)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_RatingTypeWrong(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": "bad"
|
||||||
|
}`
|
||||||
|
bookId := "18"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_RatingMin(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": -3
|
||||||
|
}`
|
||||||
|
bookId := "18"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_RatingMax(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": 15
|
||||||
|
}`
|
||||||
|
bookId := "18"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRatingUserBooksHandler_BadBookId(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"rating": 15
|
||||||
|
}`
|
||||||
|
bookId := "18574"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutReadUserBooks_NewReadOk(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"read": true
|
||||||
|
}`
|
||||||
|
bookId := "21"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutReadUserBooks_NewReadDateOk(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"read": true,
|
||||||
|
"endDate": "2025-10-20"
|
||||||
|
}`
|
||||||
|
bookId := "9"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, "2025-10-20", book.EndReadDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutReadUserBooks_UnsetEndDate(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"read": true,
|
||||||
|
"endDate": "null"
|
||||||
|
}`
|
||||||
|
bookId := "9"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, "", book.EndReadDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutReadUserBooks_UnsetReadOk(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"read": false
|
||||||
|
}`
|
||||||
|
bookId := "9"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, false, book.Read)
|
||||||
|
assert.Equal(t, "", book.EndReadDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutStartReadUserBooks_WrongDateFormat(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"startDate": "19/11/2025"
|
||||||
|
}`
|
||||||
|
bookId := "6"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutStartReadUserBooks_NewReadOk(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"startDate": "2025-11-19"
|
||||||
|
}`
|
||||||
|
bookId := "6"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, "2025-11-19", book.StartReadDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutStartReadUserBooks_Unset(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"startDate": "null"
|
||||||
|
}`
|
||||||
|
bookId := "6"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, "", book.StartReadDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutWantRead_SetTrue(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"wantread": true
|
||||||
|
}`
|
||||||
|
bookId := "17"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, true, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutWantRead_SetFalse(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"wantread": false
|
||||||
|
}`
|
||||||
|
bookId := "2"
|
||||||
|
testPutUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPutUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
||||||
|
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/ws/book/"+bookId)
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package apitest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/testutils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPutWantRead_SetTrue(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"wantread": true
|
|
||||||
}`
|
|
||||||
bookId := "17"
|
|
||||||
testPutWantReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, true, book.WantRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutWantRead_SetFalse(t *testing.T) {
|
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"wantread": false
|
|
||||||
}`
|
|
||||||
bookId := "2"
|
|
||||||
testPutWantReadUserBooks(t, payload, bookId, http.StatusOK)
|
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
|
||||||
assert.Equal(t, false, book.WantRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPutWantReadUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
|
||||||
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/ws/book/"+bookId+"/wantread")
|
|
||||||
}
|
|
||||||
@@ -21,6 +21,15 @@ type BookPostImport struct {
|
|||||||
Lang string `json:"lang" binding:"required,max=5"`
|
Lang string `json:"lang" binding:"required,max=5"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserBookPutUpdate struct {
|
||||||
|
Read *bool `json:"read"`
|
||||||
|
EndDate *string `json:"endDate"`
|
||||||
|
WantRead *bool `json:"wantread"`
|
||||||
|
Rating *int `json:"rating"`
|
||||||
|
StartDate *string `json:"startDate"`
|
||||||
|
Review *string `json:"review"`
|
||||||
|
}
|
||||||
|
|
||||||
type FileInfoPost struct {
|
type FileInfoPost struct {
|
||||||
FileID uint `json:"fileId"`
|
FileID uint `json:"fileId"`
|
||||||
FilePath string `json:"filepath"`
|
FilePath string `json:"filepath"`
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type BookGet struct {
|
|||||||
InventaireId string `json:"inventaireid"`
|
InventaireId string `json:"inventaireid"`
|
||||||
OpenLibraryId string `json:"openlibraryid"`
|
OpenLibraryId string `json:"openlibraryid"`
|
||||||
Summary string `json:"summary"`
|
Summary string `json:"summary"`
|
||||||
|
Review string `json:"review"`
|
||||||
Rating int `json:"rating"`
|
Rating int `json:"rating"`
|
||||||
Read bool `json:"read"`
|
Read bool `json:"read"`
|
||||||
WantRead bool `json:"wantread"`
|
WantRead bool `json:"wantread"`
|
||||||
|
|||||||
@@ -132,6 +132,27 @@ func TestCallInventaireEdition(t *testing.T) {
|
|||||||
result)
|
result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalInventaireEditionNoAuthor(t *testing.T) {
|
||||||
|
|
||||||
|
result, err := CallInventaireEdition(getBaseInventaireUrl(), "isbn:9782226487162", "fr")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t,
|
||||||
|
InventaireEditionDetailedSingleResult{
|
||||||
|
Id: "isbn:9782226487162",
|
||||||
|
Title: "Les Yeux de Mona",
|
||||||
|
Author: nil,
|
||||||
|
Description: "",
|
||||||
|
ISBN: "978-2-226-48716-2",
|
||||||
|
Publisher: "éditions Albin Michel",
|
||||||
|
ReleaseDate: "2024-02-01",
|
||||||
|
Image: "https://inventaire.io/img/entities/3ca857913983d694be03dee712bb2af9e2c51747",
|
||||||
|
Lang: "fr",
|
||||||
|
},
|
||||||
|
result)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCallInventaireEditionFromISBN(t *testing.T) {
|
func TestCallInventaireEditionFromISBN(t *testing.T) {
|
||||||
result, err := CallInventaireFromISBN(getBaseInventaireUrl(), "9782070379248", "fr")
|
result, err := CallInventaireFromISBN(getBaseInventaireUrl(), "9782070379248", "fr")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package inventaire
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/callapiutils"
|
"git.artlef.fr/bibliomane/internal/callapiutils"
|
||||||
@@ -32,14 +33,15 @@ func CallInventaireEditionFromWork(inventaireUrl string, workId string, lang str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return queryResult, err
|
return queryResult, err
|
||||||
}
|
}
|
||||||
queryResult.Count = int64(len(uris.Uris))
|
|
||||||
sort.Strings(uris.Uris)
|
sort.Strings(uris.Uris)
|
||||||
limitedUris := uris.Uris
|
listUris := slices.Compact(uris.Uris)
|
||||||
|
queryResult.Count = int64(len(listUris))
|
||||||
|
limitedUris := listUris
|
||||||
if limit != 0 {
|
if limit != 0 {
|
||||||
l := len(uris.Uris)
|
l := len(listUris)
|
||||||
startIndex := int(math.Min(float64(offset), float64(l)))
|
startIndex := int(math.Min(float64(offset), float64(l)))
|
||||||
endIndex := int(math.Min(float64(limit+offset), float64(l)))
|
endIndex := int(math.Min(float64(limit+offset), float64(l)))
|
||||||
limitedUris = uris.Uris[startIndex:endIndex]
|
limitedUris = listUris[startIndex:endIndex]
|
||||||
}
|
}
|
||||||
editionEntities, err := callInventaireEditionEntities(inventaireUrl, limitedUris)
|
editionEntities, err := callInventaireEditionEntities(inventaireUrl, limitedUris)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type UserBook struct {
|
|||||||
Rating int
|
Rating int
|
||||||
Read bool
|
Read bool
|
||||||
WantRead bool
|
WantRead bool
|
||||||
|
Review string
|
||||||
StartReadDate *time.Time
|
StartReadDate *time.Time
|
||||||
EndReadDate *time.Time
|
EndReadDate *time.Time
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ func computeValidationMessage(ac *appcontext.AppContext, fe *validator.FieldErro
|
|||||||
return i18nresource.GetTranslatedMessage(ac, "ValidationRequired")
|
return i18nresource.GetTranslatedMessage(ac, "ValidationRequired")
|
||||||
case "min":
|
case "min":
|
||||||
return fmt.Sprintf(i18nresource.GetTranslatedMessage(ac, "ValidationTooShort"), (*fe).Param())
|
return fmt.Sprintf(i18nresource.GetTranslatedMessage(ac, "ValidationTooShort"), (*fe).Param())
|
||||||
|
case "gte":
|
||||||
|
return fmt.Sprintf("Should be greater than %s", (*fe).Param())
|
||||||
case "max":
|
case "max":
|
||||||
return fmt.Sprintf(i18nresource.GetTranslatedMessage(ac, "ValidationTooLong"), (*fe).Param())
|
return fmt.Sprintf(i18nresource.GetTranslatedMessage(ac, "ValidationTooLong"), (*fe).Param())
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (dto.BookGet, error)
|
|||||||
var book dto.BookGet
|
var book dto.BookGet
|
||||||
query := db.Model(&model.Book{})
|
query := db.Model(&model.Book{})
|
||||||
selectQueryString := "books.title, authors.name as author, authors.id as author_id, books.isbn, books.inventaire_id, books.open_library_id, books.summary, " +
|
selectQueryString := "books.title, authors.name as author, authors.id as author_id, books.isbn, books.inventaire_id, books.open_library_id, books.summary, " +
|
||||||
"user_books.rating, user_books.read, user_books.want_read, " +
|
"user_books.review, user_books.rating, user_books.read, user_books.want_read, " +
|
||||||
"DATE(user_books.start_read_date) as start_read_date, " +
|
"DATE(user_books.start_read_date) as start_read_date, " +
|
||||||
"DATE(user_books.end_read_date) AS end_read_date, " +
|
"DATE(user_books.end_read_date) AS end_read_date, " +
|
||||||
selectStaticFilesPath()
|
selectStaticFilesPath()
|
||||||
|
|||||||
@@ -40,18 +40,21 @@ func PostImportBookHandler(ac appcontext.AppContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func saveInventaireBookToDb(ac appcontext.AppContext, inventaireEdition inventaire.InventaireEditionDetailedSingleResult, user *model.User) (*model.Book, error) {
|
func saveInventaireBookToDb(ac appcontext.AppContext, inventaireEdition inventaire.InventaireEditionDetailedSingleResult, user *model.User) (*model.Book, error) {
|
||||||
author, err := fetchOrCreateInventaireAuthor(ac, inventaireEdition.Author)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
book := model.Book{
|
book := model.Book{
|
||||||
Title: inventaireEdition.Title,
|
Title: inventaireEdition.Title,
|
||||||
SmallDescription: inventaireEdition.Description,
|
SmallDescription: inventaireEdition.Description,
|
||||||
InventaireID: inventaireEdition.Id,
|
InventaireID: inventaireEdition.Id,
|
||||||
Author: *author,
|
|
||||||
AddedBy: *user,
|
AddedBy: *user,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if inventaireEdition.Author != nil {
|
||||||
|
author, err := fetchOrCreateInventaireAuthor(ac, inventaireEdition.Author)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
book.Author = *author
|
||||||
|
}
|
||||||
|
|
||||||
if inventaireEdition.Image != "" {
|
if inventaireEdition.Image != "" {
|
||||||
cover, err := fileutils.DownloadFile(ac, inventaireEdition.Image)
|
cover, err := fileutils.DownloadFile(ac, inventaireEdition.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,7 +62,7 @@ func saveInventaireBookToDb(ac appcontext.AppContext, inventaireEdition inventai
|
|||||||
}
|
}
|
||||||
book.Cover = cover
|
book.Cover = cover
|
||||||
}
|
}
|
||||||
err = ac.Db.Save(&book).Error
|
err := ac.Db.Save(&book).Error
|
||||||
return &book, err
|
return &book, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,21 +7,35 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/appcontext"
|
"git.artlef.fr/bibliomane/internal/appcontext"
|
||||||
|
"git.artlef.fr/bibliomane/internal/dto"
|
||||||
"git.artlef.fr/bibliomane/internal/model"
|
"git.artlef.fr/bibliomane/internal/model"
|
||||||
"git.artlef.fr/bibliomane/internal/myvalidator"
|
"git.artlef.fr/bibliomane/internal/myvalidator"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PutReadUserBookHandler(ac appcontext.AppContext) {
|
func PutUserBookHandler(ac appcontext.AppContext) {
|
||||||
data, err := retrieveDataFromContext(ac)
|
bookId64, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
|
||||||
|
bookId := uint(bookId64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ac.C.JSON(http.StatusBadRequest, gin.H{"error": err})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bookId := data.BookId
|
err = myvalidator.ValidateId(ac.Db, bookId, &model.Book{})
|
||||||
user := data.User
|
if err != nil {
|
||||||
var read userbookPutRead
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
err = ac.C.ShouldBindJSON(&read)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := ac.GetAuthenticatedUser()
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var userBookPut dto.UserBookPutUpdate
|
||||||
|
err = ac.C.ShouldBindJSON(&userBookPut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return
|
||||||
@@ -32,14 +46,56 @@ func PutReadUserBookHandler(ac appcontext.AppContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userbook.Read = read.Read
|
if userBookPut.Read != nil {
|
||||||
|
err = updateReadStatus(&userbook, &userBookPut)
|
||||||
if read.EndDate != "" {
|
|
||||||
d, err := parseDate(read.EndDate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if userBookPut.WantRead != nil {
|
||||||
|
userbook.WantRead = *userBookPut.WantRead
|
||||||
|
}
|
||||||
|
if userBookPut.StartDate != nil {
|
||||||
|
d, err := parseDate(*userBookPut.StartDate)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userbook.StartReadDate = d
|
||||||
|
}
|
||||||
|
if userBookPut.Rating != nil {
|
||||||
|
err = validateRating(*userBookPut.Rating)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
}
|
||||||
|
updateRating(&userbook, &userBookPut)
|
||||||
|
}
|
||||||
|
if userBookPut.Review != nil {
|
||||||
|
userbook.Review = *userBookPut.Review
|
||||||
|
}
|
||||||
|
ac.Db.Save(&userbook)
|
||||||
|
ac.C.String(http.StatusOK, "Success")
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateRating(rating int) error {
|
||||||
|
//struct used for validation
|
||||||
|
var ratingStruct struct {
|
||||||
|
Rating int `validate:"gte=0,lte=10"`
|
||||||
|
}
|
||||||
|
ratingStruct.Rating = rating
|
||||||
|
validate := validator.New()
|
||||||
|
return validate.Struct(ratingStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateReadStatus(userbook *model.UserBook, userBookPut *dto.UserBookPutUpdate) error {
|
||||||
|
userbook.Read = *userBookPut.Read
|
||||||
|
|
||||||
|
if userBookPut.EndDate != nil && *userBookPut.EndDate != "" {
|
||||||
|
d, err := parseDate(*userBookPut.EndDate)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
userbook.EndReadDate = d
|
userbook.EndReadDate = d
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,84 +108,11 @@ func PutReadUserBookHandler(ac appcontext.AppContext) {
|
|||||||
if !userbook.Read {
|
if !userbook.Read {
|
||||||
userbook.EndReadDate = nil
|
userbook.EndReadDate = nil
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
ac.Db.Save(&userbook)
|
|
||||||
ac.C.String(http.StatusOK, "Success")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutWantReadUserBookHandler(ac appcontext.AppContext) {
|
func updateRating(userbook *model.UserBook, userBookPut *dto.UserBookPutUpdate) {
|
||||||
data, err := retrieveDataFromContext(ac)
|
userbook.Rating = *userBookPut.Rating
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bookId := data.BookId
|
|
||||||
user := data.User
|
|
||||||
var wantread userbookPutWantRead
|
|
||||||
err = ac.C.ShouldBindJSON(&wantread)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userbook.WantRead = wantread.WantRead
|
|
||||||
ac.Db.Save(&userbook)
|
|
||||||
ac.C.String(http.StatusOK, "Success")
|
|
||||||
}
|
|
||||||
|
|
||||||
func PutStartReadUserBookHandler(ac appcontext.AppContext) {
|
|
||||||
data, err := retrieveDataFromContext(ac)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bookId := data.BookId
|
|
||||||
user := data.User
|
|
||||||
|
|
||||||
var startDateToParse userbookPutStartRead
|
|
||||||
err = ac.C.ShouldBindJSON(&startDateToParse)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := parseDate(startDateToParse.StartDate)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userbook.StartReadDate = d
|
|
||||||
|
|
||||||
ac.Db.Save(&userbook)
|
|
||||||
ac.C.String(http.StatusOK, "Success")
|
|
||||||
}
|
|
||||||
|
|
||||||
func PutRateUserBookHandler(ac appcontext.AppContext) {
|
|
||||||
data, err := retrieveDataFromContext(ac)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bookId := data.BookId
|
|
||||||
user := data.User
|
|
||||||
var rating userbookPutRating
|
|
||||||
err = ac.C.ShouldBindJSON(&rating)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userbook.Rating = rating.Rating
|
|
||||||
|
|
||||||
//if rated, set to "read" (a rating = 0 means unrated)
|
//if rated, set to "read" (a rating = 0 means unrated)
|
||||||
if userbook.Rating > 0 {
|
if userbook.Rating > 0 {
|
||||||
@@ -137,30 +120,6 @@ func PutRateUserBookHandler(ac appcontext.AppContext) {
|
|||||||
//if set to read, remove want read
|
//if set to read, remove want read
|
||||||
userbook.WantRead = false
|
userbook.WantRead = false
|
||||||
}
|
}
|
||||||
ac.Db.Save(&userbook)
|
|
||||||
ac.C.String(http.StatusOK, "Success")
|
|
||||||
}
|
|
||||||
|
|
||||||
type userbookPutRead struct {
|
|
||||||
Read bool `json:"read"`
|
|
||||||
EndDate string `json:"endDate"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type userbookPutWantRead struct {
|
|
||||||
WantRead bool `json:"wantread"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type userbookPutRating struct {
|
|
||||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type userbookPutStartRead struct {
|
|
||||||
StartDate string `json:"startDate" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiCallData struct {
|
|
||||||
BookId uint
|
|
||||||
User model.User
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDate(dateToParse string) (*time.Time, error) {
|
func parseDate(dateToParse string) (*time.Time, error) {
|
||||||
@@ -173,27 +132,6 @@ func parseDate(dateToParse string) (*time.Time, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveDataFromContext(ac appcontext.AppContext) (apiCallData, error) {
|
|
||||||
bookId64, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
|
|
||||||
bookId := uint(bookId64)
|
|
||||||
if err != nil {
|
|
||||||
ac.C.JSON(http.StatusBadRequest, gin.H{"error": err})
|
|
||||||
return apiCallData{}, err
|
|
||||||
}
|
|
||||||
err = myvalidator.ValidateId(ac.Db, bookId, &model.Book{})
|
|
||||||
if err != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return apiCallData{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
user, fetchUserErr := ac.GetAuthenticatedUser()
|
|
||||||
if fetchUserErr != nil {
|
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
|
||||||
return apiCallData{}, fetchUserErr
|
|
||||||
}
|
|
||||||
return apiCallData{BookId: bookId, User: user}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchOrCreateUserBook(ac appcontext.AppContext, bookId uint, user *model.User) (model.UserBook, error) {
|
func fetchOrCreateUserBook(ac appcontext.AppContext, bookId uint, user *model.User) (model.UserBook, error) {
|
||||||
var userbook model.UserBook
|
var userbook model.UserBook
|
||||||
res := ac.Db.Where("user_id = ? AND book_id = ?", user.ID, bookId).First(&userbook)
|
res := ac.Db.Where("user_id = ? AND book_id = ?", user.ID, bookId).First(&userbook)
|
||||||
|
|||||||
@@ -58,17 +58,8 @@ func Setup(config *config.Config) *gin.Engine {
|
|||||||
ws.GET("/book/:id", func(c *gin.Context) {
|
ws.GET("/book/:id", func(c *gin.Context) {
|
||||||
routes.GetBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.GetBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
})
|
})
|
||||||
ws.PUT("/book/:id/read", func(c *gin.Context) {
|
ws.PUT("/book/:id", func(c *gin.Context) {
|
||||||
routes.PutReadUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.PutUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
})
|
|
||||||
ws.PUT("/book/:id/wantread", func(c *gin.Context) {
|
|
||||||
routes.PutWantReadUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
|
||||||
})
|
|
||||||
ws.PUT("/book/:id/startread", func(c *gin.Context) {
|
|
||||||
routes.PutStartReadUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
|
||||||
})
|
|
||||||
ws.PUT("/book/:id/rate", func(c *gin.Context) {
|
|
||||||
routes.PutRateUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
|
||||||
})
|
})
|
||||||
ws.POST("/book", func(c *gin.Context) {
|
ws.POST("/book", func(c *gin.Context) {
|
||||||
routes.PostBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.PostBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"git.artlef.fr/bibliomane/internal/config"
|
"git.artlef.fr/bibliomane/internal/config"
|
||||||
"git.artlef.fr/bibliomane/internal/setup"
|
"git.artlef.fr/bibliomane/internal/setup"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetup() *gin.Engine {
|
func TestSetup() *gin.Engine {
|
||||||
@@ -62,5 +61,7 @@ func TestBookPutCallWithDemoPayload(t *testing.T, payload string, bookId string,
|
|||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
assert.Equal(t, expectedCode, w.Code)
|
if w.Code != expectedCode {
|
||||||
|
t.Errorf("%s", w.Body.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
applicationVersion := "0.3.0"
|
applicationVersion := "0.4.0"
|
||||||
c := config.LoadConfig(applicationVersion)
|
c := config.LoadConfig(applicationVersion)
|
||||||
r := setup.Setup(&c)
|
r := setup.Setup(&c)
|
||||||
r.Run(":" + c.Port)
|
r.Run(":" + c.Port)
|
||||||
|
|||||||
Reference in New Issue
Block a user