нужно добавить пользователю поля, а также изменить логику на страницах с действиями читателя и создателя
This commit is contained in:
parent
b3f98c6325
commit
864614acea
14
build.gradle
14
build.gradle
@ -16,22 +16,18 @@ jar {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(':front'))
|
implementation(project(':front'))
|
||||||
|
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-devtools'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
|
implementation 'com.h2database:h2:2.1.210'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'com.auth0:java-jwt:4.4.0'
|
implementation 'com.auth0:java-jwt:4.4.0'
|
||||||
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
|
implementation 'org.hibernate.validator:hibernate-validator'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
|
||||||
implementation 'org.webjars:bootstrap:5.1.3'
|
implementation 'org.webjars:bootstrap:5.1.3'
|
||||||
implementation 'org.webjars:jquery:3.6.0'
|
implementation 'org.webjars:jquery:3.6.0'
|
||||||
implementation 'org.webjars:font-awesome:6.1.0'
|
implementation 'org.webjars:font-awesome:6.1.0'
|
||||||
|
|
||||||
implementation 'com.h2database:h2:2.1.210'
|
|
||||||
implementation 'org.hibernate.validator:hibernate-validator'
|
|
||||||
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
//implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
|
//implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
|
||||||
|
|
||||||
|
BIN
data.mv.db
BIN
data.mv.db
Binary file not shown.
274
data.trace.db
274
data.trace.db
@ -993,3 +993,277 @@ Caused by: org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikola
|
|||||||
at org.h2.mvstore.FileStore.open(FileStore.java:163)
|
at org.h2.mvstore.FileStore.open(FileStore.java:163)
|
||||||
at org.h2.mvstore.MVStore.<init>(MVStore.java:444)
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:444)
|
||||||
... 62 more
|
... 62 more
|
||||||
|
2023-05-05 12:45:34 database: flush
|
||||||
|
org.h2.message.DbException: Внутренняя ошибка: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]"
|
||||||
|
General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]" [50000-210]
|
||||||
|
at org.h2.message.DbException.get(DbException.java:216)
|
||||||
|
at org.h2.message.DbException.convert(DbException.java:414)
|
||||||
|
at org.h2.mvstore.db.Store.lambda$new$0(Store.java:120)
|
||||||
|
at org.h2.mvstore.MVStore.handleException(MVStore.java:3296)
|
||||||
|
at org.h2.mvstore.MVStore.panic(MVStore.java:585)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:461)
|
||||||
|
at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4056)
|
||||||
|
at org.h2.mvstore.db.Store.<init>(Store.java:129)
|
||||||
|
at org.h2.engine.Database.<init>(Database.java:324)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:92)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:222)
|
||||||
|
at org.h2.engine.Engine.createSession(Engine.java:201)
|
||||||
|
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338)
|
||||||
|
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:122)
|
||||||
|
at org.h2.Driver.connect(Driver.java:59)
|
||||||
|
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100)
|
||||||
|
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
|
||||||
|
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.getConnectionUrl(H2ConsoleAutoConfiguration.java:94)
|
||||||
|
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
|
||||||
|
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
|
||||||
|
at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395)
|
||||||
|
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
|
||||||
|
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
|
||||||
|
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
|
||||||
|
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
|
||||||
|
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
|
||||||
|
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
|
||||||
|
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
|
||||||
|
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
|
||||||
|
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
|
||||||
|
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.logDataSources(H2ConsoleAutoConfiguration.java:86)
|
||||||
|
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.lambda$h2Console$0(H2ConsoleAutoConfiguration.java:69)
|
||||||
|
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.withThreadContextClassLoader(H2ConsoleAutoConfiguration.java:78)
|
||||||
|
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.h2Console(H2ConsoleAutoConfiguration.java:69)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
|
||||||
|
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
|
||||||
|
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
|
||||||
|
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
|
||||||
|
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1324)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
|
||||||
|
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
|
||||||
|
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:208)
|
||||||
|
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:199)
|
||||||
|
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:94)
|
||||||
|
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:85)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:261)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:235)
|
||||||
|
at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:52)
|
||||||
|
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5144)
|
||||||
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
|
||||||
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
|
||||||
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1383)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
|
||||||
|
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
|
||||||
|
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
|
||||||
|
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:916)
|
||||||
|
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:886)
|
||||||
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
|
||||||
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
|
||||||
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1383)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
|
||||||
|
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
|
||||||
|
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
|
||||||
|
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:916)
|
||||||
|
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:252)
|
||||||
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
|
||||||
|
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:430)
|
||||||
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
|
||||||
|
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:926)
|
||||||
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
|
||||||
|
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:485)
|
||||||
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123)
|
||||||
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104)
|
||||||
|
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:486)
|
||||||
|
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:210)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:183)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:161)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:578)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||||
|
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
|
||||||
|
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
|
||||||
|
at com.LabWork.app.AppApplication.main(AppApplication.java:9)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
|
||||||
|
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
|
||||||
|
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Внутренняя ошибка: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]"
|
||||||
|
General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]" [50000-210]
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:496)
|
||||||
|
... 103 more
|
||||||
|
Caused by: org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]
|
||||||
|
at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004)
|
||||||
|
at org.h2.mvstore.FileStore.open(FileStore.java:163)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:444)
|
||||||
|
... 97 more
|
||||||
|
2023-05-05 12:45:35 database: flush
|
||||||
|
org.h2.message.DbException: Внутренняя ошибка: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]"
|
||||||
|
General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]" [50000-210]
|
||||||
|
at org.h2.message.DbException.get(DbException.java:216)
|
||||||
|
at org.h2.message.DbException.convert(DbException.java:414)
|
||||||
|
at org.h2.mvstore.db.Store.lambda$new$0(Store.java:120)
|
||||||
|
at org.h2.mvstore.MVStore.handleException(MVStore.java:3296)
|
||||||
|
at org.h2.mvstore.MVStore.panic(MVStore.java:585)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:461)
|
||||||
|
at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4056)
|
||||||
|
at org.h2.mvstore.db.Store.<init>(Store.java:129)
|
||||||
|
at org.h2.engine.Database.<init>(Database.java:324)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:92)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:222)
|
||||||
|
at org.h2.engine.Engine.createSession(Engine.java:201)
|
||||||
|
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338)
|
||||||
|
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:122)
|
||||||
|
at org.h2.Driver.connect(Driver.java:59)
|
||||||
|
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100)
|
||||||
|
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
|
||||||
|
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
|
||||||
|
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:284)
|
||||||
|
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:177)
|
||||||
|
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:36)
|
||||||
|
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119)
|
||||||
|
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:255)
|
||||||
|
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:230)
|
||||||
|
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207)
|
||||||
|
at org.hibernate.boot.model.relational.Database.<init>(Database.java:44)
|
||||||
|
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:218)
|
||||||
|
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:191)
|
||||||
|
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:138)
|
||||||
|
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1350)
|
||||||
|
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1421)
|
||||||
|
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66)
|
||||||
|
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376)
|
||||||
|
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
|
||||||
|
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
|
||||||
|
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
|
||||||
|
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1130)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:905)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||||
|
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
|
||||||
|
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
|
||||||
|
at com.LabWork.app.AppApplication.main(AppApplication.java:9)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
|
||||||
|
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
|
||||||
|
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Внутренняя ошибка: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]"
|
||||||
|
General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]" [50000-210]
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:496)
|
||||||
|
... 64 more
|
||||||
|
Caused by: org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]
|
||||||
|
at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004)
|
||||||
|
at org.h2.mvstore.FileStore.open(FileStore.java:163)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:444)
|
||||||
|
... 58 more
|
||||||
|
2023-05-05 12:45:37 database: flush
|
||||||
|
org.h2.message.DbException: Внутренняя ошибка: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]"
|
||||||
|
General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]" [50000-210]
|
||||||
|
at org.h2.message.DbException.get(DbException.java:216)
|
||||||
|
at org.h2.message.DbException.convert(DbException.java:414)
|
||||||
|
at org.h2.mvstore.db.Store.lambda$new$0(Store.java:120)
|
||||||
|
at org.h2.mvstore.MVStore.handleException(MVStore.java:3296)
|
||||||
|
at org.h2.mvstore.MVStore.panic(MVStore.java:585)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:461)
|
||||||
|
at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4056)
|
||||||
|
at org.h2.mvstore.db.Store.<init>(Store.java:129)
|
||||||
|
at org.h2.engine.Database.<init>(Database.java:324)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:92)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:222)
|
||||||
|
at org.h2.engine.Engine.createSession(Engine.java:201)
|
||||||
|
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338)
|
||||||
|
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:122)
|
||||||
|
at org.h2.Driver.connect(Driver.java:59)
|
||||||
|
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100)
|
||||||
|
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
|
||||||
|
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
|
||||||
|
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:284)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:41)
|
||||||
|
at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:63)
|
||||||
|
at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcDatabaseMetaData(ImprovedExtractionContextImpl.java:70)
|
||||||
|
at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.processTableResultSet(InformationExtractorJdbcDatabaseMetaDataImpl.java:64)
|
||||||
|
at org.hibernate.tool.schema.extract.internal.AbstractInformationExtractorImpl.getTables(AbstractInformationExtractorImpl.java:564)
|
||||||
|
at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.getTablesInformation(DatabaseInformationImpl.java:122)
|
||||||
|
at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:71)
|
||||||
|
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:225)
|
||||||
|
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:126)
|
||||||
|
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:284)
|
||||||
|
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$5(SchemaManagementToolCoordinator.java:143)
|
||||||
|
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
|
||||||
|
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:140)
|
||||||
|
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:336)
|
||||||
|
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:415)
|
||||||
|
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1425)
|
||||||
|
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66)
|
||||||
|
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376)
|
||||||
|
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
|
||||||
|
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
|
||||||
|
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
|
||||||
|
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1130)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:905)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||||
|
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
|
||||||
|
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
|
||||||
|
at com.LabWork.app.AppApplication.main(AppApplication.java:9)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
|
||||||
|
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
|
||||||
|
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Внутренняя ошибка: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]"
|
||||||
|
General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]" [50000-210]
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:496)
|
||||||
|
... 68 more
|
||||||
|
Caused by: org.h2.mvstore.MVStoreException: The file is locked: D:/RaspaevNikolayPIbd-21/2_sem/IP/IP_PIbd-21_Raspaev_NI/data.mv.db [2.1.210/7]
|
||||||
|
at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004)
|
||||||
|
at org.h2.mvstore.FileStore.open(FileStore.java:163)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:444)
|
||||||
|
... 62 more
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { useRoutes, Outlet, BrowserRouter } from 'react-router-dom';
|
import { Routes, BrowserRouter, Route } from 'react-router-dom';
|
||||||
import Creator from './MainS/Creator';
|
import Creator from './MainS/Creator';
|
||||||
import Reader from './MainS/Reader';
|
import Reader from './MainS/Reader';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import CreatorAction from './Main/CreatorAction';
|
import CreatorAction from './Main/CreatorAction';
|
||||||
import ReaderAction from './Main/ReaderAction';
|
import ReaderAction from './Main/ReaderAction';
|
||||||
import MangaPage from './Main/MangaPage';
|
import UsersPage from './Main/UsersPage';
|
||||||
import Catalog from './Main/Catalog';
|
import Catalog from './Main/Catalog';
|
||||||
|
import LoginPage from './Main/LoginPage';
|
||||||
|
import SingupPage from './Main/SingupPage';
|
||||||
|
import PrivateRoutes from "./components/PrivateRoutes";
|
||||||
|
import MangaPage from "./Main/MangaPage";
|
||||||
|
|
||||||
function Router(props) {
|
function Router(props) {
|
||||||
return useRoutes(props.rootRoute);
|
return useRoutes(props.rootRoute);
|
||||||
@ -14,30 +18,41 @@ function Router(props) {
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
const routes = [
|
const routes = [
|
||||||
{ index: true, element: <Reader /> },
|
{ index: true, element: <Reader /> },
|
||||||
{ path: 'creator', element: <Creator />, label: 'Creator' },
|
|
||||||
{ path: 'reader', element: <Reader />, label: 'Reader' },
|
|
||||||
{ path: 'creatorAction', element: <CreatorAction />, label: 'CreatorAction' },
|
|
||||||
{ path: 'readerAction', element: <ReaderAction />, label: 'ReaderAction' },
|
|
||||||
{ path: 'catalog', element: <Catalog />, label: 'Catalog' },
|
|
||||||
{ path: 'mangapage', element: <MangaPage /> },
|
|
||||||
];
|
|
||||||
const links = routes.filter(route => route.hasOwnProperty('label'));
|
|
||||||
const rootRoute = [
|
|
||||||
{ path: '/', element: render(links), children: routes }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function render(links) {
|
const links = [
|
||||||
return (
|
{ path: 'catalog', label: "Catalog", userGroup: "AUTH" },
|
||||||
<>
|
{ path: 'readerAction', label: "ReaderAction", userGroup: "USER" },
|
||||||
<Header links={links} />
|
{ path: 'creatorAction', label: "CreatorAction", userGroup: "ADMIN" },
|
||||||
<Outlet />
|
{ path: 'creator', label: "Creator", userGroup: "ADMIN" },
|
||||||
</>
|
{ path: 'reader', label: "Reader", userGroup: "ADMIN" },
|
||||||
);
|
{ path: 'users', label: "Users", userGroup: "ADMIN" }
|
||||||
}
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<>
|
||||||
<Router rootRoute={ rootRoute } />
|
<BrowserRouter>
|
||||||
</BrowserRouter>
|
<Header links={links}></Header>
|
||||||
|
<div className="content-div">
|
||||||
|
<Routes>
|
||||||
|
<Route element={<LoginPage />} path="/login" />
|
||||||
|
<Route element={<SingupPage />} path="/singup" />
|
||||||
|
<Route element={<PrivateRoutes userGroup="AUTH" />}>
|
||||||
|
<Route element={<MangaPage />} path="/mangapage" />
|
||||||
|
<Route element={<Catalog />} path="/catalog" />
|
||||||
|
<Route element={<Catalog />} path="*" />
|
||||||
|
</Route>
|
||||||
|
<Route element={<PrivateRoutes userGroup="USER" />}>
|
||||||
|
<Route element={<ReaderAction />} path="/readerAction" />
|
||||||
|
</Route>
|
||||||
|
<Route element={<PrivateRoutes userGroup="ADMIN" />}>
|
||||||
|
<Route element={<UsersPage />} path="/users" />
|
||||||
|
<Route element={<Creator />} path="/creator" />
|
||||||
|
<Route element={<Reader />} path="/reader" />
|
||||||
|
<Route element={<CreatorAction />} path="/creatorAction" />
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
</div>
|
||||||
|
</BrowserRouter>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
8
front/src/Dto/user-singup-dto.js
Normal file
8
front/src/Dto/user-singup-dto.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default class UserSignupDto {
|
||||||
|
constructor(args) {
|
||||||
|
this.login = args.login;
|
||||||
|
this.email = args.email;
|
||||||
|
this.password = args.password;
|
||||||
|
this.passwordConfirm = args.passwordConfirm;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,9 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import '../components/Banner/banner.css'
|
import { NavLink } from 'react-router-dom';
|
||||||
import Banner from '../components/Banner/Banner.jsx'
|
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
|
||||||
import MangaDto from "../Dto/Manga-Dto";
|
|
||||||
|
|
||||||
export default function Catalog() {
|
export default function Catalog() {
|
||||||
|
|
||||||
const host = "http://localhost:8080/api";
|
const host = "http://localhost:8080/api/1.0";
|
||||||
|
|
||||||
const [mangs, setMangs] = useState([]);
|
const [mangs, setMangs] = useState([]);
|
||||||
|
|
||||||
@ -17,8 +14,18 @@ export default function Catalog() {
|
|||||||
console.log(mangs);
|
console.log(mangs);
|
||||||
},[]);
|
},[]);
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
const getMangs = async function () {
|
const getMangs = async function () {
|
||||||
const response = await fetch(host + "/manga");
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const response = await fetch(host + "/manga", requestParams);
|
||||||
const _data = await response.json()
|
const _data = await response.json()
|
||||||
console.log(_data);
|
console.log(_data);
|
||||||
return _data;
|
return _data;
|
||||||
@ -26,7 +33,6 @@ export default function Catalog() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="p-2 catalog_article">
|
<article className="p-2 catalog_article">
|
||||||
<Banner />
|
|
||||||
<div className = "catalog_wrapper">
|
<div className = "catalog_wrapper">
|
||||||
<h1>Каталог</h1>
|
<h1>Каталог</h1>
|
||||||
<div className="p-2 d-flex flex-wrap">
|
<div className="p-2 d-flex flex-wrap">
|
||||||
|
@ -8,7 +8,7 @@ import EditMangaModal from "../components/Modal/EditMangaModal";
|
|||||||
|
|
||||||
export default function CreatorAction() {
|
export default function CreatorAction() {
|
||||||
|
|
||||||
const host = "http://localhost:8080/api";
|
const host = "http://localhost:8080/api/1.0";
|
||||||
|
|
||||||
const [creatorData, setCreatorData] = useState([]);
|
const [creatorData, setCreatorData] = useState([]);
|
||||||
|
|
||||||
@ -24,13 +24,23 @@ export default function CreatorAction() {
|
|||||||
|
|
||||||
const [mangaModel, setMangaModel] = useState(new MangaDto({}));
|
const [mangaModel, setMangaModel] = useState(new MangaDto({}));
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCreatorData()
|
getCreatorData()
|
||||||
.then(_data =>setCreatorData(_data));
|
.then(_data =>setCreatorData(_data));
|
||||||
},[]);
|
},[]);
|
||||||
|
|
||||||
const getCreatorData = async function () {
|
const getCreatorData = async function () {
|
||||||
const response = await fetch(host + "/creator");
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const response = await fetch(host + "/creator", requestParams);
|
||||||
const _data = await response.json()
|
const _data = await response.json()
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
@ -49,6 +59,7 @@ export default function CreatorAction() {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/creator/` + id, requestParams);
|
const response = await fetch(host + `/creator/` + id, requestParams);
|
||||||
@ -79,6 +90,7 @@ export default function CreatorAction() {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
},
|
},
|
||||||
body: JSON.stringify(mangaModel),
|
body: JSON.stringify(mangaModel),
|
||||||
};
|
};
|
||||||
@ -108,6 +120,7 @@ export default function CreatorAction() {
|
|||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/manga/` + id, requestParams);
|
const response = await fetch(host + `/manga/` + id, requestParams);
|
||||||
@ -131,6 +144,7 @@ export default function CreatorAction() {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
},
|
},
|
||||||
body: JSON.stringify(mangaModel),
|
body: JSON.stringify(mangaModel),
|
||||||
};
|
};
|
||||||
|
90
front/src/Main/LoginPage.jsx
Normal file
90
front/src/Main/LoginPage.jsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
const hostURL = "http://localhost:8080";
|
||||||
|
|
||||||
|
const LoginPage = function () {
|
||||||
|
|
||||||
|
const loginInput = useRef();
|
||||||
|
const passwordInput = useRef();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const login = async function (login, password) {
|
||||||
|
const requestParams = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({login: login, password: password}),
|
||||||
|
};
|
||||||
|
const response = await fetch(hostURL + "/jwt/login", requestParams);
|
||||||
|
const result = await response.text();
|
||||||
|
if (response.status === 200) {
|
||||||
|
localStorage.setItem("token", result);
|
||||||
|
localStorage.setItem("user", login);
|
||||||
|
getRole(result);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
localStorage.removeItem("role");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRole = async function (token) {
|
||||||
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const requestUrl = hostURL + `/who_am_i?token=${token}`;
|
||||||
|
const response = await fetch(requestUrl, requestParams);
|
||||||
|
const result = await response.text();
|
||||||
|
localStorage.setItem("role", result);
|
||||||
|
window.dispatchEvent(new Event("storage"));
|
||||||
|
navigate("/reader");
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginFormOnSubmit = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
login(loginInput.current.value, passwordInput.current.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<form onSubmit={(event) => loginFormOnSubmit(event)}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="mb-1">Login</p>
|
||||||
|
<input className="form-control"
|
||||||
|
type="text" required autoFocus
|
||||||
|
ref={loginInput} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="mb-1">Password</p>
|
||||||
|
<input className="form-control"
|
||||||
|
type="password" required
|
||||||
|
ref={passwordInput} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<button type="submit" className="btn btn-success">
|
||||||
|
Sing in
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<span>Not a member yet? </span>
|
||||||
|
<Link to="/singup">Sing Up here</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoginPage;
|
@ -8,7 +8,11 @@ export default function MangaPage() {
|
|||||||
|
|
||||||
const [readerData, setReaderData] = useState([]);
|
const [readerData, setReaderData] = useState([]);
|
||||||
|
|
||||||
const host = "http://localhost:8080/api";
|
const host = "http://localhost:8080/api/1.0";
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const quryString = window.location.search;
|
const quryString = window.location.search;
|
||||||
@ -29,6 +33,7 @@ export default function MangaPage() {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/manga/` + id + `/readers`, requestParams);
|
const response = await fetch(host + `/manga/` + id + `/readers`, requestParams);
|
||||||
@ -52,6 +57,7 @@ export default function MangaPage() {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/manga/` + id, requestParams);
|
const response = await fetch(host + `/manga/` + id, requestParams);
|
||||||
|
@ -6,7 +6,7 @@ import AddMangaReaderModal from "../components/Modal/AddMangaReaderModal";
|
|||||||
|
|
||||||
export default function ReaderAction() {
|
export default function ReaderAction() {
|
||||||
|
|
||||||
const host = "http://localhost:8080/api";
|
const host = "http://localhost:8080/api/1.0";
|
||||||
|
|
||||||
const [mangaData, setMangaData] = useState([]);
|
const [mangaData, setMangaData] = useState([]);
|
||||||
|
|
||||||
@ -22,6 +22,10 @@ export default function ReaderAction() {
|
|||||||
|
|
||||||
const [mangaName, setMangaName] = useState("");
|
const [mangaName, setMangaName] = useState("");
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const quryString = window.location.search;
|
const quryString = window.location.search;
|
||||||
const urlParams = new URLSearchParams(quryString);
|
const urlParams = new URLSearchParams(quryString);
|
||||||
@ -37,14 +41,26 @@ export default function ReaderAction() {
|
|||||||
},[]);
|
},[]);
|
||||||
|
|
||||||
const getReaderData = async function () {
|
const getReaderData = async function () {
|
||||||
const response = await fetch(host + "/reader");
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const response = await fetch(host + "/reader", requestParams);
|
||||||
const _data = await response.json()
|
const _data = await response.json()
|
||||||
console.log(_data);
|
console.log(_data);
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMangaData = async function () {
|
const getMangaData = async function () {
|
||||||
const response = await fetch(host + "/manga");
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const response = await fetch(host + "/manga", requestParams);
|
||||||
const _data = await response.json()
|
const _data = await response.json()
|
||||||
console.log(_data);
|
console.log(_data);
|
||||||
return _data;
|
return _data;
|
||||||
@ -64,6 +80,7 @@ export default function ReaderAction() {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/reader/` + id, requestParams);
|
const response = await fetch(host + `/reader/` + id, requestParams);
|
||||||
@ -93,6 +110,7 @@ export default function ReaderAction() {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/manga/${mangaId}?chapterCount=${chapterCount}`, requestParams);
|
const response = await fetch(host + `/manga/${mangaId}?chapterCount=${chapterCount}`, requestParams);
|
||||||
@ -120,6 +138,7 @@ export default function ReaderAction() {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
console.log(host + `/reader/${readerId}/removeManga?mangaId=${id}`, requestParams);
|
console.log(host + `/reader/${readerId}/removeManga?mangaId=${id}`, requestParams);
|
||||||
@ -143,6 +162,7 @@ export default function ReaderAction() {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
console.log(host + `/reader/${readerId}/addManga?mangaId=${mangaId}`, requestParams);
|
console.log(host + `/reader/${readerId}/addManga?mangaId=${mangaId}`, requestParams);
|
||||||
|
88
front/src/Main/SingupPage.jsx
Normal file
88
front/src/Main/SingupPage.jsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
const hostURL = "http://localhost:8080";
|
||||||
|
|
||||||
|
const SingupPage = function () {
|
||||||
|
|
||||||
|
const loginInput = useRef();
|
||||||
|
const emailInput = useRef();
|
||||||
|
const passwordInput = useRef();
|
||||||
|
const passwordConfirmInput = useRef();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const singup = async function (userSinginDto) {
|
||||||
|
const requestParams = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify(userSinginDto),
|
||||||
|
};
|
||||||
|
console.log(hostURL + "/sing_up");
|
||||||
|
console.log(userSinginDto);
|
||||||
|
const response = await fetch(hostURL + "/sing_up", requestParams);
|
||||||
|
const result = await response.text();
|
||||||
|
alert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const singupFormOnSubmit = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const userSinginDto = {
|
||||||
|
login: loginInput.current.value,
|
||||||
|
email: emailInput.current.value,
|
||||||
|
password: passwordInput.current.value,
|
||||||
|
passwordConfirm: passwordConfirmInput.current.value
|
||||||
|
}
|
||||||
|
singup(userSinginDto);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<form onSubmit={(event) => singupFormOnSubmit(event)}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="mb-1">Login</p>
|
||||||
|
<input className="form-control"
|
||||||
|
type="text" required maxLength="64"
|
||||||
|
ref={loginInput} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="mb-1">Email</p>
|
||||||
|
<input className="form-control"
|
||||||
|
type="text" required
|
||||||
|
ref={emailInput} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="mb-1">Password</p>
|
||||||
|
<input className="form-control"
|
||||||
|
type="password" required minLength="3" maxLength="64"
|
||||||
|
ref={passwordInput} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="mb-1">Confirm Password</p>
|
||||||
|
<input className="form-control"
|
||||||
|
type="password" required minLength="3" maxLength="64"
|
||||||
|
ref={passwordConfirmInput} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<button type="submit" className="btn btn-success">
|
||||||
|
Create account
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<span>Already have an account? </span>
|
||||||
|
<Link to="/login">Sing In here</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingupPage;
|
112
front/src/Main/UsersPage.jsx
Normal file
112
front/src/Main/UsersPage.jsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
const hostURL = "http://localhost:8080";
|
||||||
|
const host = hostURL + "/api/1.0";
|
||||||
|
|
||||||
|
const UsersPage = function () {
|
||||||
|
|
||||||
|
const [users, setUsers] = useState([]);
|
||||||
|
const [pageNumbers, setPageNumbers] = useState([]);
|
||||||
|
const [pageNumber, setPageNumber] = useState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getUsers(1);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUsers = async function (page) {
|
||||||
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const requestUrl = host + `/users?page=${page}`;
|
||||||
|
const response = await fetch(requestUrl, requestParams);
|
||||||
|
const data = await response.json();
|
||||||
|
setUsers(data.first.content);
|
||||||
|
setPageNumber(data.first.number);
|
||||||
|
setPageNumbers(data.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeUser = async function (id) {
|
||||||
|
const requestParams = {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const requestUrl = host + `/user/${id}`;
|
||||||
|
await fetch(requestUrl, requestParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageButtonOnClick = function (page) {
|
||||||
|
getUsers(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeButtonOnClick = function (id) {
|
||||||
|
const confirmResult = confirm("Are you sure you want to remove " +
|
||||||
|
"the selected user?");
|
||||||
|
if (confirmResult === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
removeUser(id).then(() => getUsers(pageNumber + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="table-shell mb-3">
|
||||||
|
<table className="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style={{ width: "10%" }} scope="col">#</th>
|
||||||
|
<th style={{ width: "15%" }} scope="col">ID</th>
|
||||||
|
<th style={{ width: "30%" }} scope="col">Login</th>
|
||||||
|
<th style={{ width: "30%" }} scope="col">Email</th>
|
||||||
|
<th style={{ width: "15%" }} scope="col">Role</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{users.map((user, index) => (
|
||||||
|
<tr>
|
||||||
|
<th style={{ width: "10%" }} scope="row">{index}</th>
|
||||||
|
<td style={{ width: "15%" }}>{user.id}</td>
|
||||||
|
<td style={{ width: "30%" }}>{user.login}</td>
|
||||||
|
<td style={{ width: "30%" }}>{user.email}</td>
|
||||||
|
<td style={{ width: "15%" }}>{user.role}</td>
|
||||||
|
{user.login !== localStorage.getItem("user") ?
|
||||||
|
<td style={{ width: "1%" }}>
|
||||||
|
<button className="btn btn-secondary btn-sm"
|
||||||
|
onClick={() => removeButtonOnClick(user.id)}>
|
||||||
|
del
|
||||||
|
</button>
|
||||||
|
</td> : null}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Pages:
|
||||||
|
</p>
|
||||||
|
<nav>
|
||||||
|
<ul className="pagination">
|
||||||
|
{pageNumbers.map((number) => (
|
||||||
|
<li className={`page-item ${number === pageNumber + 1 ? "active" : ""}`}
|
||||||
|
onClick={() => pageButtonOnClick(number)}>
|
||||||
|
<a className="page-link" href="#">{number}</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UsersPage;
|
@ -4,7 +4,7 @@ import MangaDto from '../Dto/Manga-Dto';
|
|||||||
|
|
||||||
export default function Creator() {
|
export default function Creator() {
|
||||||
|
|
||||||
const host = "http://localhost:8080/api";
|
const host = "http://localhost:8080/api/1.0";
|
||||||
|
|
||||||
const [creatorId, setCreatorId] = useState(0);
|
const [creatorId, setCreatorId] = useState(0);
|
||||||
|
|
||||||
@ -16,6 +16,9 @@ export default function Creator() {
|
|||||||
|
|
||||||
const [data, setData] = useState([]);
|
const [data, setData] = useState([]);
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
const table = document.getElementById("tbody");
|
const table = document.getElementById("tbody");
|
||||||
|
|
||||||
@ -24,15 +27,23 @@ export default function Creator() {
|
|||||||
},[]);
|
},[]);
|
||||||
|
|
||||||
const getData = async function () {
|
const getData = async function () {
|
||||||
const response = await fetch(host + "/creator");
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const requestUrl = host + `/creator`;
|
||||||
|
const response = await fetch(requestUrl, requestParams);
|
||||||
setData(await response.json())
|
setData(await response.json())
|
||||||
console.log(data);
|
console.log(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const create = async function (){
|
const create = async function (){
|
||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -52,6 +63,7 @@ export default function Creator() {
|
|||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -69,6 +81,9 @@ export default function Creator() {
|
|||||||
}
|
}
|
||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
await fetch(host + `/creator/`, requestParams);
|
await fetch(host + `/creator/`, requestParams);
|
||||||
}
|
}
|
||||||
@ -81,6 +96,7 @@ export default function Creator() {
|
|||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ import TableReader from '../components/Table/TableReader';
|
|||||||
|
|
||||||
export default function ReaderS() {
|
export default function ReaderS() {
|
||||||
|
|
||||||
const host = "http://localhost:8080/api";
|
const host = "http://localhost:8080/api/1.0";
|
||||||
|
|
||||||
const [readerId, setReaderId] = useState(0);
|
const [readerId, setReaderId] = useState(0);
|
||||||
|
|
||||||
@ -15,8 +15,9 @@ export default function ReaderS() {
|
|||||||
|
|
||||||
const [data, setData] = useState([]);
|
const [data, setData] = useState([]);
|
||||||
|
|
||||||
|
const getTokenForHeader = function () {
|
||||||
|
return "Bearer " + localStorage.getItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
const table = document.getElementById("tbody");
|
const table = document.getElementById("tbody");
|
||||||
|
|
||||||
@ -25,21 +26,30 @@ export default function ReaderS() {
|
|||||||
console.log(2);
|
console.log(2);
|
||||||
},[]);
|
},[]);
|
||||||
|
|
||||||
|
|
||||||
const getData = async function () {
|
const getData = async function () {
|
||||||
const response = await fetch(host + "/reader");
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const requestUrl = host + `/reader`;
|
||||||
|
const response = await fetch(requestUrl, requestParams);
|
||||||
setData(await response.json())
|
setData(await response.json())
|
||||||
console.log(data);
|
console.log(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const create = async function (){
|
const create = async function (){
|
||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/reader?readerName=${readerName}&password=${password}`, requestParams);
|
const response = await fetch(host + `/reader?readerName=${readerName}&password=${password}`, requestParams);
|
||||||
|
alert(response);
|
||||||
|
console.log(response);
|
||||||
getData();
|
getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +65,7 @@ export default function ReaderS() {
|
|||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response = await fetch(host + `/reader/` + id, requestParams);
|
const response = await fetch(host + `/reader/` + id, requestParams);
|
||||||
@ -70,6 +81,9 @@ export default function ReaderS() {
|
|||||||
}
|
}
|
||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
await fetch(host + `/reader/`, requestParams);
|
await fetch(host + `/reader/`, requestParams);
|
||||||
getData();
|
getData();
|
||||||
@ -83,6 +97,7 @@ export default function ReaderS() {
|
|||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -100,6 +115,7 @@ export default function ReaderS() {
|
|||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -112,6 +128,7 @@ export default function ReaderS() {
|
|||||||
const requestParams = {
|
const requestParams = {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
|
"Authorization": getTokenForHeader(),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import React from 'react'
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import banner1 from "../../../img/popular_1.jpg";
|
|
||||||
import banner2 from "../../../img/popular_2.jpg";
|
|
||||||
import banner3 from "../../../img/popular_3.jpg"
|
|
||||||
|
|
||||||
export default function Banner() {
|
|
||||||
const length = 3;
|
|
||||||
var old = length - 1;
|
|
||||||
var current = 0;
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [bannerState, setBannerState] = useState(["show", "hide", "hide"]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = window.setInterval(() => {
|
|
||||||
setBannerState([
|
|
||||||
...bannerState,
|
|
||||||
(bannerState[current] = "show"),
|
|
||||||
(bannerState[old] = "hide"),
|
|
||||||
]);
|
|
||||||
//setBannerState([...bannerState, ]);
|
|
||||||
|
|
||||||
console.info("Banner changed");
|
|
||||||
|
|
||||||
old = current;
|
|
||||||
current++;
|
|
||||||
|
|
||||||
if (current === length) {
|
|
||||||
current = 0;
|
|
||||||
}
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.clearInterval(timer);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="d-flex align-items-center flex-column" id="banner">
|
|
||||||
<a className={bannerState[0]} style={{ cursor: "pointer" }}><img src={banner1}/></a>
|
|
||||||
<a className={bannerState[1]} style={{ cursor: "pointer" }}><img src={banner2}/></a>
|
|
||||||
<a className={bannerState[2]} style={{ cursor: "pointer" }}><img src={banner3}/></a>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
#banner {
|
|
||||||
margin: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes newAnim {
|
|
||||||
from { opacity: 0; }
|
|
||||||
to { opacity: 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner img {
|
|
||||||
max-width: 90%;
|
|
||||||
border-radius: 5px;
|
|
||||||
animation: newAnim 1s forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner a.show {
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner a.hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.show {
|
|
||||||
max-height: 200px;
|
|
||||||
width: auto;
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity 1s, visibility 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.hide {
|
|
||||||
max-height: 0;
|
|
||||||
width: 0;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 1s, visibility 0s 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 700px){
|
|
||||||
#banner{width: 0px;}
|
|
||||||
#banner_2{width: 0px;}
|
|
||||||
#banner img.show {
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 1s, visibility 0s 1s;
|
|
||||||
}
|
|
||||||
#banner h3{
|
|
||||||
font-size: 0em;
|
|
||||||
}
|
|
||||||
#banner_2 h3{
|
|
||||||
font-size: 0em;
|
|
||||||
}
|
|
||||||
#banner_2 img.show {
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 1s, visibility 0s 1s;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,34 @@
|
|||||||
import { NavLink } from 'react-router-dom';
|
import {NavLink, useNavigate} from 'react-router-dom';
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
export default function Header(props) {
|
export default function Header(props) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const logoutButtonOnClick = function () {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
localStorage.removeItem("role");
|
||||||
|
window.dispatchEvent(new Event("storage"));
|
||||||
|
navigate("/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
const [userRole, setUserRole] = useState("NONE");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener("storage", () => {
|
||||||
|
getUserRole();
|
||||||
|
});
|
||||||
|
getUserRole();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const getUserRole = function () {
|
||||||
|
const role = localStorage.getItem("role") || "NONE";
|
||||||
|
setUserRole(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
const validate = function (userGroup) {
|
||||||
|
return (userGroup === "AUTH" && userRole !== "NONE") || (userGroup === userRole);
|
||||||
|
}
|
||||||
|
console.log(userRole);
|
||||||
return (
|
return (
|
||||||
<nav className="navbar navbar-expand-lg navbar-dark">
|
<nav className="navbar navbar-expand-lg navbar-dark">
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
@ -11,14 +39,27 @@ export default function Header(props) {
|
|||||||
</button>
|
</button>
|
||||||
<div className="collapse navbar-collapse" id="navbarNav">
|
<div className="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul className="navbar-nav">
|
<ul className="navbar-nav">
|
||||||
{props.links.map(route =>
|
{props.links.map(route =>{
|
||||||
|
if (validate(route.userGroup)) {
|
||||||
|
return (
|
||||||
<li key={route.path}
|
<li key={route.path}
|
||||||
className="nav-item">
|
className="nav-item">
|
||||||
<NavLink className="nav-link" to={route.path}>
|
<NavLink className="nav-link" to={route.path}>
|
||||||
{route.label}
|
{route.label}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
);}}
|
||||||
)}
|
)}
|
||||||
|
{userRole === "NONE"?
|
||||||
|
null
|
||||||
|
:
|
||||||
|
<div className="border-bottom pb-3 mb-3">
|
||||||
|
<button className="btn btn-primary"
|
||||||
|
onClick={logoutButtonOnClick}>
|
||||||
|
Log Out
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
46
front/src/components/PrivateRoutes.jsx
Normal file
46
front/src/components/PrivateRoutes.jsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import {Navigate, Outlet, useNavigate} from 'react-router-dom';
|
||||||
|
import {useEffect} from "react";
|
||||||
|
|
||||||
|
const PrivateRoutes = (props) => {
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener("storage", () => {
|
||||||
|
let token = localStorage.getItem("token");
|
||||||
|
if (token) {
|
||||||
|
getRole(token).then((role) => {
|
||||||
|
if (localStorage.getItem("role") != role) {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
localStorage.removeItem("role");
|
||||||
|
window.dispatchEvent(new Event("storage"));
|
||||||
|
navigate("/catalog");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const getRole = async function (token) {
|
||||||
|
const requestParams = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const requestUrl = `http://localhost:8080/who_am_i?token=${token}`;
|
||||||
|
const response = await fetch(requestUrl, requestParams);
|
||||||
|
return await response.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
let isAllowed = false;
|
||||||
|
let userRole = localStorage.getItem("role");
|
||||||
|
if ((props.userGroup === "AUTH" && userRole) || (props.userGroup === userRole)) {
|
||||||
|
isAllowed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isAllowed ? <Outlet /> : <Navigate to="/login" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PrivateRoutes;
|
@ -2,9 +2,12 @@ package com.LabWork.app.MangaStore.controller;
|
|||||||
|
|
||||||
|
|
||||||
import com.LabWork.app.MangaStore.configuration.OpenAPI30Configuration;
|
import com.LabWork.app.MangaStore.configuration.OpenAPI30Configuration;
|
||||||
|
import com.LabWork.app.MangaStore.model.Default.UserRole;
|
||||||
import com.LabWork.app.MangaStore.model.Dto.ReaderMangaDto;
|
import com.LabWork.app.MangaStore.model.Dto.ReaderMangaDto;
|
||||||
import com.LabWork.app.MangaStore.model.Dto.SupportDto.MangaDto;
|
import com.LabWork.app.MangaStore.model.Dto.SupportDto.MangaDto;
|
||||||
import com.LabWork.app.MangaStore.service.ReaderService;
|
import com.LabWork.app.MangaStore.service.ReaderService;
|
||||||
|
import com.LabWork.app.MangaStore.util.validation.ValidationException;
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -31,9 +34,14 @@ public class ReaderController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ReaderMangaDto createReader(@RequestParam("readerName") String readerName,
|
@Secured({UserRole.AsString.ADMIN})
|
||||||
|
public String createReader(@RequestParam("readerName") String readerName,
|
||||||
@RequestParam("password") String password) {
|
@RequestParam("password") String password) {
|
||||||
return new ReaderMangaDto(readerService.addReader(readerName, password));
|
try {
|
||||||
|
return new ReaderMangaDto(readerService.addReader(readerName, password)).toString();
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
@ -56,6 +64,7 @@ public class ReaderController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
|
@Secured({UserRole.AsString.USER})
|
||||||
public ReaderMangaDto deleteReader(@PathVariable Long id) {
|
public ReaderMangaDto deleteReader(@PathVariable Long id) {
|
||||||
return new ReaderMangaDto(readerService.deleteReader(id));
|
return new ReaderMangaDto(readerService.deleteReader(id));
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class UserService implements UserDetailsService {
|
|||||||
throw new ValidationException("Passwords not equals");
|
throw new ValidationException("Passwords not equals");
|
||||||
}
|
}
|
||||||
final User user = new User(login, email, passwordEncoder.encode(password), role);
|
final User user = new User(login, email, passwordEncoder.encode(password), role);
|
||||||
validatorUtil.validate(user);
|
//validatorUtil.validate(user);
|
||||||
return userRepository.save(user);
|
return userRepository.save(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,3 +9,5 @@ spring.jpa.hibernate.ddl-auto=update
|
|||||||
spring.h2.console.enabled=true
|
spring.h2.console.enabled=true
|
||||||
spring.h2.console.settings.trace=false
|
spring.h2.console.settings.trace=false
|
||||||
spring.h2.console.settings.web-allow-others=false
|
spring.h2.console.settings.web-allow-others=false
|
||||||
|
jwt.dev-token=my-secret-jwt
|
||||||
|
jwt.dev=true
|
77
src/test/java/com/LabWork/app/JpaUserTests.java
Normal file
77
src/test/java/com/LabWork/app/JpaUserTests.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package com.LabWork.app;
|
||||||
|
|
||||||
|
import com.LabWork.app.MangaStore.model.Default.User;
|
||||||
|
import com.LabWork.app.MangaStore.model.Default.UserRole;
|
||||||
|
import com.LabWork.app.MangaStore.service.Exception.UserNotFoundException;
|
||||||
|
import com.LabWork.app.MangaStore.service.UserService;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
public class JpaUserTests {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(JpaUserTests.class);
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUserCreate() {
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
final User user = userService.addUser("User 1", "email@gmail.com",
|
||||||
|
"123456", "123456", UserRole.USER);
|
||||||
|
log.info("testUserCreate: " + user.toString());
|
||||||
|
Assertions.assertNotNull(user.getId());
|
||||||
|
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUserRead() {
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
final User user = userService.addUser("User 2", "email@gmail.com",
|
||||||
|
"123456", "123456", UserRole.USER);
|
||||||
|
log.info("testUserRead[0]: " + user.toString());
|
||||||
|
final User findUser = userService.findUser(user.getId());
|
||||||
|
log.info("testUserRead[1]: " + findUser.toString());
|
||||||
|
Assertions.assertEquals(user, findUser);
|
||||||
|
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUserReadNotFound() {
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
Assertions.assertThrows(UserNotFoundException.class, () -> userService.findUser(-1L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUserReadAll() {
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
userService.addUser("User 3", "email@gmail.com", "123456",
|
||||||
|
"123456", UserRole.USER);
|
||||||
|
userService.addUser("User 4", "email@gmail.com", "123456",
|
||||||
|
"123456", UserRole.USER);
|
||||||
|
final List<User> users = userService.findAllUsers();
|
||||||
|
log.info("testUserReadAll: " + users.toString());
|
||||||
|
Assertions.assertEquals(users.size(), 2);
|
||||||
|
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUserReadAllEmpty() {
|
||||||
|
userService.deleteAllUsers();
|
||||||
|
final List<User> users = userService.findAllUsers();
|
||||||
|
log.info("testUserReadAllEmpty: " + users.toString());
|
||||||
|
Assertions.assertEquals(users.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user