Initial commit
This commit is contained in:
commit
b8e617ef6c
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@ -0,0 +1,18 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
64
.env.example
Normal file
64
.env.example
Normal file
@ -0,0 +1,64 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=laravel
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/.phpunit.cache
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpactor.json
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
||||
url-ext.xpi
|
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
# vi: ft=dockerfile
|
||||
FROM docker.io/nginx
|
||||
|
||||
ADD nginx.proxy.conf /nginx.conf
|
||||
|
||||
CMD ["nginx", "-c", "/nginx.conf", "-g", "daemon off;"]
|
40
api/.gitignore
vendored
Normal file
40
api/.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Kotlin ###
|
||||
.kotlin
|
7
api/application.properties
Normal file
7
api/application.properties
Normal file
@ -0,0 +1,7 @@
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
spring.datasource.url=jdbc:postgresql://localhost:5432/applications
|
||||
spring.datasource.username=applications
|
||||
spring.datasource.password=applications
|
||||
|
||||
# spring.sql.init.schema-locations=classpath:schema.sql
|
||||
# spring.sql.init.mode=always
|
49
api/build.gradle.kts
Normal file
49
api/build.gradle.kts
Normal file
@ -0,0 +1,49 @@
|
||||
plugins {
|
||||
id("org.springframework.boot") version "3.3.1"
|
||||
id("io.spring.dependency-management") version "1.1.5"
|
||||
kotlin("plugin.jpa") version "1.9.24"
|
||||
kotlin("jvm") version "1.9.24"
|
||||
kotlin("plugin.spring") version "1.9.24"
|
||||
}
|
||||
|
||||
group = "com.andr3h3nriqu3s"
|
||||
|
||||
version = "0.0.1-SNAPSHOT"
|
||||
|
||||
java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }
|
||||
|
||||
repositories { mavenCentral() }
|
||||
|
||||
dependencies {
|
||||
implementation("org.postgresql:postgresql")
|
||||
implementation("org.springframework.security:spring-security-crypto:6.0.3")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-mustache")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
implementation("org.hibernate.orm:hibernate-community-dialects")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
runtimeOnly("com.h2database:h2")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
||||
implementation("org.bouncycastle:bcprov-jdk18on:1.76")
|
||||
}
|
||||
|
||||
//kotlin { compilerOptions { freeCompilerArgs.addAll("-Xjsr305=strict") } compiler { jvm { target = JavaLanguageVersion.of(17) } } }
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll("-Xjsr305=strict")
|
||||
}
|
||||
|
||||
jvmToolchain(17)
|
||||
}
|
||||
|
||||
tasks.withType<Test> { useJUnitPlatform() }
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
BIN
api/data/testdb.mv.db
Normal file
BIN
api/data/testdb.mv.db
Normal file
Binary file not shown.
337
api/data/testdb.trace.db
Normal file
337
api/data/testdb.trace.db
Normal file
@ -0,0 +1,337 @@
|
||||
2024-07-06 21:04:26.959072+01:00 jdbc[3]: exception
|
||||
org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "t.id" not found [42122-224]
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:514)
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
|
||||
at org.h2.message.DbException.get(DbException.java:223)
|
||||
at org.h2.message.DbException.get(DbException.java:199)
|
||||
at org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3492)
|
||||
at org.h2.jdbc.JdbcResultSet.getString(JdbcResultSet.java:301)
|
||||
at com.zaxxer.hikari.pool.HikariProxyResultSet.getString(HikariProxyResultSet.java)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyToken$lambda$0(User.kt:186)
|
||||
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
|
||||
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
|
||||
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:754)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:767)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:820)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyToken(User.kt:181)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyTokenThrow(User.kt:203)
|
||||
at com.andr3h3nriqu3s.applications.ApplicationsController.submitText(ApplicationsController.kt:30)
|
||||
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 kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
|
||||
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113)
|
||||
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:207)
|
||||
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod$KotlinDelegate.invokeFunction(InvocableHandlerMethod.java:334)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:252)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
|
||||
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
|
||||
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
|
||||
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
|
||||
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
|
||||
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
|
||||
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
|
||||
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
|
||||
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
|
||||
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
|
||||
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
|
||||
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
|
||||
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
|
||||
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
|
||||
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
|
||||
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
|
||||
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
|
||||
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
|
||||
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
|
||||
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.base/java.lang.Thread.run(Thread.java:840)
|
||||
2024-07-06 21:25:03.965298+01:00 jdbc[3]: exception
|
||||
org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "u.id" not found [42122-224]
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:514)
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
|
||||
at org.h2.message.DbException.get(DbException.java:223)
|
||||
at org.h2.message.DbException.get(DbException.java:199)
|
||||
at org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3492)
|
||||
at org.h2.jdbc.JdbcResultSet.getString(JdbcResultSet.java:301)
|
||||
at com.zaxxer.hikari.pool.HikariProxyResultSet.getString(HikariProxyResultSet.java)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyToken$lambda$0(User.kt:186)
|
||||
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
|
||||
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
|
||||
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:754)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:767)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:820)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyToken(User.kt:181)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyTokenThrow(User.kt:203)
|
||||
at com.andr3h3nriqu3s.applications.ApplicationsController.submitText(ApplicationsController.kt:30)
|
||||
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 kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
|
||||
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113)
|
||||
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:207)
|
||||
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod$KotlinDelegate.invokeFunction(InvocableHandlerMethod.java:334)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:252)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
|
||||
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
|
||||
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
|
||||
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
|
||||
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
|
||||
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
|
||||
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
|
||||
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
|
||||
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
|
||||
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
|
||||
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
|
||||
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
|
||||
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
|
||||
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
|
||||
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
|
||||
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
|
||||
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
|
||||
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
|
||||
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
|
||||
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.base/java.lang.Thread.run(Thread.java:840)
|
||||
2024-07-06 21:30:12.489279+01:00 jdbc[3]: exception
|
||||
org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "password" not found [42122-224]
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:514)
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
|
||||
at org.h2.message.DbException.get(DbException.java:223)
|
||||
at org.h2.message.DbException.get(DbException.java:199)
|
||||
at org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3492)
|
||||
at org.h2.jdbc.JdbcResultSet.getString(JdbcResultSet.java:301)
|
||||
at com.zaxxer.hikari.pool.HikariProxyResultSet.getString(HikariProxyResultSet.java)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyToken$lambda$0(User.kt:189)
|
||||
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
|
||||
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
|
||||
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:754)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:767)
|
||||
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:820)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyToken(User.kt:181)
|
||||
at com.andr3h3nriqu3s.applications.SessionService.verifyTokenThrow(User.kt:203)
|
||||
at com.andr3h3nriqu3s.applications.ApplicationsController.submitText(ApplicationsController.kt:30)
|
||||
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 kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
|
||||
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113)
|
||||
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:207)
|
||||
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod$KotlinDelegate.invokeFunction(InvocableHandlerMethod.java:334)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:252)
|
||||
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
|
||||
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
|
||||
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
|
||||
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
|
||||
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
|
||||
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
|
||||
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
|
||||
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
|
||||
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
|
||||
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
|
||||
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
|
||||
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
|
||||
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
|
||||
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
|
||||
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
|
||||
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
|
||||
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
|
||||
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
|
||||
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
|
||||
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
|
||||
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
|
||||
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
|
||||
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.base/java.lang.Thread.run(Thread.java:840)
|
||||
2024-07-06 21:58:05.248085+01:00 jdbc[3]: exception
|
||||
org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-224]
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:690)
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
|
||||
at org.h2.message.DbException.get(DbException.java:223)
|
||||
at org.h2.message.DbException.get(DbException.java:199)
|
||||
at org.h2.message.DbException.get(DbException.java:188)
|
||||
at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1425)
|
||||
at org.h2.jdbc.JdbcConnection.getMetaData(JdbcConnection.java:334)
|
||||
at com.zaxxer.hikari.pool.ProxyConnection.getMetaData(ProxyConnection.java:371)
|
||||
at com.zaxxer.hikari.pool.HikariProxyConnection.getMetaData(HikariProxyConnection.java)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$1.execute(JdbcEnvironmentInitiator.java:295)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$1.execute(JdbcEnvironmentInitiator.java:291)
|
||||
at org.hibernate.jdbc.WorkExecutor.executeReturningWork(WorkExecutor.java:58)
|
||||
at org.hibernate.jdbc.AbstractReturningWork.accept(AbstractReturningWork.java:34)
|
||||
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:70)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:290)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:123)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:77)
|
||||
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130)
|
||||
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
|
||||
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238)
|
||||
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215)
|
||||
at org.hibernate.boot.model.relational.Database.<init>(Database.java:45)
|
||||
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:221)
|
||||
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:189)
|
||||
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:171)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1431)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1502)
|
||||
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75)
|
||||
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:390)
|
||||
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:366)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1835)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
|
||||
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
|
||||
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:952)
|
||||
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624)
|
||||
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
|
||||
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
|
||||
at com.andr3h3nriqu3s.applications.ApplicationsApplicationKt.main(ApplicationsApplication.kt:13)
|
||||
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:50)
|
||||
2024-07-06 21:58:05.249168+01:00 jdbc[3]: exception
|
||||
org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-224]
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:690)
|
||||
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
|
||||
at org.h2.message.DbException.get(DbException.java:223)
|
||||
at org.h2.message.DbException.get(DbException.java:199)
|
||||
at org.h2.message.DbException.get(DbException.java:188)
|
||||
at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1425)
|
||||
at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:660)
|
||||
at com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:258)
|
||||
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.closeConnection(DatasourceConnectionProviderImpl.java:127)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.releaseConnection(JdbcEnvironmentInitiator.java:442)
|
||||
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:108)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:290)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:123)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:77)
|
||||
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130)
|
||||
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
|
||||
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238)
|
||||
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215)
|
||||
at org.hibernate.boot.model.relational.Database.<init>(Database.java:45)
|
||||
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:221)
|
||||
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:189)
|
||||
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:171)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1431)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1502)
|
||||
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75)
|
||||
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:390)
|
||||
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:366)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1835)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
|
||||
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
|
||||
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:952)
|
||||
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624)
|
||||
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
|
||||
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
|
||||
at com.andr3h3nriqu3s.applications.ApplicationsApplicationKt.main(ApplicationsApplication.kt:13)
|
||||
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:50)
|
BIN
api/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
api/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
api/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
api/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
api/gradlew
vendored
Executable file
249
api/gradlew
vendored
Executable file
@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
api/gradlew.bat
vendored
Normal file
92
api/gradlew.bat
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
1
api/settings.gradle.kts
Normal file
1
api/settings.gradle.kts
Normal file
@ -0,0 +1 @@
|
||||
rootProject.name = "applications"
|
0
api/sqlitesample.db
Normal file
0
api/sqlitesample.db
Normal file
@ -0,0 +1,11 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class ApplicationsApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<ApplicationsApplication>(*args)
|
||||
}
|
@ -0,0 +1,499 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
import java.sql.ResultSet
|
||||
import java.util.UUID
|
||||
import kotlin.collections.setOf
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.jdbc.core.RowMapper
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.PutMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestHeader
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
data class Application(
|
||||
var id: String,
|
||||
var url: String,
|
||||
var original_url: String?,
|
||||
var unique_url: String?,
|
||||
var title: String,
|
||||
var user_id: String,
|
||||
var extra_data: String,
|
||||
var payrange: String,
|
||||
var status: Int,
|
||||
var flairs: List<Flair>
|
||||
) {
|
||||
companion object : RowMapper<Application> {
|
||||
override public fun mapRow(rs: ResultSet, rowNum: Int): Application {
|
||||
return Application(
|
||||
rs.getString("id"),
|
||||
rs.getString("url"),
|
||||
rs.getString("original_url"),
|
||||
rs.getString("unique_url"),
|
||||
rs.getString("title"),
|
||||
rs.getString("user_id"),
|
||||
rs.getString("extra_data"),
|
||||
rs.getString("payrange"),
|
||||
rs.getInt("status"),
|
||||
emptyList()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class SubmitRequest(val text: String)
|
||||
|
||||
data class ListRequest(val status: Int?)
|
||||
|
||||
data class StatusRequest(val id: String, val status: Int)
|
||||
|
||||
data class FlairRequest(val id: String, val text: String)
|
||||
|
||||
data class UpdateUrl(val id: String, val url: String)
|
||||
|
||||
@RestController
|
||||
@ControllerAdvice
|
||||
@RequestMapping("/api/application")
|
||||
class ApplicationsController(
|
||||
val sessionService: SessionService,
|
||||
val applicationService: ApplicationService,
|
||||
val flairService: FlairService
|
||||
) {
|
||||
|
||||
@PostMapping(path = ["/text"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun submitText(
|
||||
@RequestBody submit: SubmitRequest,
|
||||
@RequestHeader("token") token: String
|
||||
): Int {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
|
||||
var text = submit.text.replace("=\n", "")
|
||||
|
||||
var urls: List<String> = emptyList()
|
||||
|
||||
while (true) {
|
||||
var index = text.indexOf("href")
|
||||
|
||||
if (index == -1) {
|
||||
break
|
||||
}
|
||||
|
||||
var new_url = StringBuilder()
|
||||
|
||||
var found_start = false
|
||||
|
||||
while (true) {
|
||||
if (found_start) {
|
||||
if (text[index] == '"') {
|
||||
break
|
||||
}
|
||||
new_url.append(text[index])
|
||||
} else if (text[index] == '"') {
|
||||
found_start = true
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
text = text.substring(index)
|
||||
|
||||
urls = urls.plus(new_url.toString().replace("&", "&").replace("=3D", "="))
|
||||
}
|
||||
|
||||
print("found: ")
|
||||
print(urls.size)
|
||||
print(" links\n")
|
||||
|
||||
urls = urls.filter { predicate -> predicate.contains("jobListing") }
|
||||
|
||||
print("found fileted: ")
|
||||
print(urls.size)
|
||||
print(" links\n")
|
||||
|
||||
urls = urls.toSet().toList()
|
||||
|
||||
print("removed duplicates: ")
|
||||
print(urls.size)
|
||||
print(" links\n")
|
||||
|
||||
var client = OkHttpClient()
|
||||
|
||||
var applications =
|
||||
urls.map { elm ->
|
||||
var request =
|
||||
Request.Builder()
|
||||
.url(elm)
|
||||
.header(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (X11; Linux x86_64; rv:127.0) Gecko/20100101 Firefox/127.0"
|
||||
)
|
||||
.addHeader(
|
||||
"Accept",
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
|
||||
)
|
||||
.addHeader(
|
||||
"Cookie",
|
||||
"gdId=aafdcb86-c37d-4bfd-8d84-4a07f11dbfc2; AWSALB=Qj3Rvldo90lFQhsChPHFXcGlVxdaZOEwr1ZP4d+whxBTlXCprKj+utUCz4DHXoC6fFrewDdFdRCPBbM0v2WQQdY4URUD4lYXd0GsBEWS/5AzZX0i9yk4C7Cfz5xA; AWSALBCORS=Qj3Rvldo90lFQhsChPHFXcGlVxdaZOEwr1ZP4d+whxBTlXCprKj+utUCz4DHXoC6fFrewDdFdRCPBbM0v2WQQdY4URUD4lYXd0GsBEWS/5AzZX0i9yk4C7Cfz5xA; indeedCtk=1i17t757dk2mo801; at=Sf_nQa0d6HxrGoYn305KELOfsWT0o-KrKdraenJrTJMqApEH4LO70x3i0oOafGWes13u8kOSq8PzPD1pZAxAVOEz0hrNnOhRnLGl3Ako4I-CYx_oCB_YhFe7M-do__yNC-ipCVlbzUujwQzCW83mKFLMHk9N12RSjhzsPEQi6Xw4n66wvXSttDChGCpY-BMSn862U-OQ9gnNzy3j214vctizTPC3g2Ig7Qysg3AY7lo-HPkHaq9fojbituLfbtgtpkCDtWAwR2-3XCWu6d2H_gk7ZWn6CH1FgLf640fd1Kep7K3kArceNq046PEalzHnJMLPSnvusS_jJatdk-x4k2rxF1FJvK0MLkPiKr39V8i7J27uOMwFLRD-49EoJUOZzTxQ1wb3lyt503NuwPhYolRGr3Xla2b6wyzYRSk2e-RHHElzvCn-FlWXaTQqEiZXKEjAGihlagUz8HFmY6bRf0FLCKvA26oVjT1vEoICmn32FOHr9M65YDllTbgHj3dDeTUczzxf_nrDSyide_UL08LsZIYJAtyueUSBqvqq49WlKemvhyKBMUloNP68A_MfT5suKPasvQu-n_ZvXahY7O5KbgtIR0QVnSimFC8yaVy8Sqjo5cq2f1VnZ6kxXj9frSK-v_jz1J7hobOAo8Mlfy_EfzBDV_3nywqjT1pKgzRRmHcNLnj_cn2rPga3NUjxpYzl485eevPDv9Gj62qAMHh1w5S6v1QkSBmgaSyKpBKYD1zD86JLJ6Upf0bVM8WcHv9u33GuKX0CgC_P-P3189AgLgtISr-2NuIaNTkKMxenagCvri6oGLj6OYMD6nO9JQ_jKUqS6ShRMhDD9K1bSUE42c2_ePhBDLWFyb3AZiJvVjcL1v1k1dO93jCn7XUQZkE7x7m1QeGC0f_5OK1IZeGuJn8Jsx-u2EvT7DNSV0LNY1hfIXauy9KCLFdTeoqDuGSumi81cg; uc=8013A8318C98C5171B57B9070099BAD115C8BBA5C5A6DB94DFFE7C86F37B699E2B54A4621F700A694011D5B5CA447CCC87B1BAC35D51A1AA5B5FF13CBDC5343400624A80C8E3C3A1966ED67EBC62D473CD7C57C9E6D138AD745B36C8625AD88EA13CE3458B51AD202B52198961B4D49007278A9385005B27B951F0F7091D61DCBBD54D21C8CFBCAD7AABEF4EA398F978; trs=direct:direct:direct:2024-06-25+07%3A59%3A23.686:undefined:undefined; cf_clearance=IZpDoUoDUUNidzYbSZRoIq6S93FXgL7hmz6.PdfEiUM-1720205316-1.0.1.1-tNL38ZNHbQw9XbL3J9g4oL4aHwiAoXXuYdOb4Xi8Z3B4yWKOuL31FrrPrqPRcxVUV7BNEdlqSMaNF3k8q.Tv0A; rl_session=RudderEncrypt%3AU2FsdGVkX19OL1VCjdlEuacjPBxOQ%2FsqFNPp5d9Dke5bKES7onFGAEFzkA4iuW3rfqQ8v2sfoX19gn7Zm3Qd83i6PWHRHESeelsza78DN%2B2U7IwWQEiyEeptsuZyTPhHxb5ALLCzUhgHcvnsh3GhQw%3D%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX19%2BQEGQCkE9Cg3Ikh5t8h65RqO0N24wvgA%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2B1EoAGj4RTTyGWbZRPkyuua9oOW4YQPaE%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX18STRtzoe4K%2FzJKt8zfNqQwMj7KTzQDhfQ%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX1%2B5Kbrex9bI6O0Gr524R6IRASVZGgrWNco%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19X88n4GXRAtkOTDXcuHojO%2BetO8p7n37y2YLe6nWW5P87Stu9l86nJ4zGDs7e8D5MEUPW6KrCywQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19MgsL8FFX%2BSjRpwcg0nu4XxNDvIPdg2WGEivR2%2BsH1%2BqAvvlaEZmiQ; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18kgmzvlkMRtIo%2BzqUQ%2FVRfcuCvngKkmV8qAgqKAKraZOr9Qpqc6loH; _cfuvid=ezdGXFBaF3Eh.jiKZrHkmaV7GItIbZ4qPUy7gOyHgns-1720604124536-0.0.1.1-604800000; gdGPCset=true; _urc=293647244; AFSID=MTQ3YTQxNzEtZmYwMC00N2Y0LWJiOGMtNzVjMmRjZWM5MTQ4; gdsid=1720604123405:1720637554591:4466F8BAFD3D2D34B6058423B0F90392; JSESSIONID=BA9AA08792C5E981A69CF079E7A91B35; GSESSIONID=undefined; cass=0; asst=1720637634.1; __cf_bm=6b1QlZvq2zEE.Cqvcg0g2a0OiPObgL0IKFr.vZwZSwQ-1720637555-1.0.1.1-qaRfjwA.xRIpqzfJiksMvc_hWVvVnfGJ1YnRToNwK.m3Od0BXKUvOVnvhrpiR9bP311eCdI.EAYQZvKpwD7KHQ; bs=oiDddWzpeaDeES0KI7rnsQ:NDp0g4i9mXeF0vvvvYq2Ud_auNQosyTqd2NVCprviXG0nOGhPzqbVJa16DxpiFQkIluzbbDJqHLht66Dwrqn4yi7u_FvaGOojP_y91QEUZU:Hex7BRo2zXhuIdlGhiQR8uO5nGn2VCjpx6dF2aJPIxk"
|
||||
)
|
||||
.addHeader("Accept-Language", "en-US,en;q=0.7,pt;q=0.3")
|
||||
.addHeader("Accept-Encoding", "gzip, deflate, br, zstd")
|
||||
.addHeader("Connection", "keep-alive")
|
||||
.build()
|
||||
|
||||
var new_url: String =
|
||||
client.newCall(request).execute().use { response ->
|
||||
print("response:")
|
||||
print(response)
|
||||
print("\n")
|
||||
response.request.url.toString()
|
||||
}
|
||||
|
||||
var unique: String? = new_url!!.split("?")[0]
|
||||
|
||||
var original_url: String? = elm
|
||||
|
||||
if (new_url == elm) {
|
||||
original_url = null
|
||||
unique = null
|
||||
}
|
||||
|
||||
Thread.sleep(2000)
|
||||
|
||||
print("Got new url!\n")
|
||||
|
||||
Application(
|
||||
UUID.randomUUID().toString(),
|
||||
new_url,
|
||||
original_url,
|
||||
unique,
|
||||
"New Aplication",
|
||||
user.id,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
applications =
|
||||
applications.filter { elm -> applicationService.createApplication(user, elm) }
|
||||
|
||||
print("created new: ")
|
||||
print(applications.size)
|
||||
print(" links\n")
|
||||
|
||||
return applications.size
|
||||
}
|
||||
|
||||
@PostMapping(path = ["/text/flair"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun textFlair(
|
||||
@RequestBody info: FlairRequest,
|
||||
@RequestHeader("token") token: String
|
||||
): Int {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
val application = applicationService.findApplicationById(user, info.id)
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
val flairs = flairService.listUser(user)
|
||||
|
||||
var count = 0
|
||||
|
||||
for (flair: Flair in flairs) {
|
||||
val regex =
|
||||
Regex(
|
||||
".*" + flair.expr + ".*",
|
||||
setOf(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL)
|
||||
)
|
||||
|
||||
if (regex.matches(info.text)) {
|
||||
count += 1
|
||||
flairService.linkFlair(application, flair)
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
@PostMapping(path = ["/list"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun list(
|
||||
@RequestBody info: ListRequest,
|
||||
@RequestHeader("token") token: String
|
||||
): List<Application> {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
return applicationService.findAll(user, info)
|
||||
}
|
||||
|
||||
@GetMapping(path = ["/active"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun active(@RequestHeader("token") token: String): Application? {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
val possibleApplications = applicationService.findAll(user, ListRequest(1))
|
||||
if (possibleApplications.size == 0) {
|
||||
return null
|
||||
}
|
||||
return applicationService.findApplicationById(user, possibleApplications[0].id)
|
||||
}
|
||||
|
||||
@PutMapping(path = ["/status"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun status(
|
||||
@RequestBody info: StatusRequest,
|
||||
@RequestHeader("token") token: String,
|
||||
): Application {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
var application = applicationService.findApplicationById(user, info.id)
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
application.status = info.status
|
||||
|
||||
applicationService.update(application)
|
||||
|
||||
return application
|
||||
}
|
||||
|
||||
@PutMapping(path = ["/update"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun update(
|
||||
@RequestBody info: Application,
|
||||
@RequestHeader("token") token: String
|
||||
): Application {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
var application = applicationService.findApplicationById(user, info.id)
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
applicationService.update(info)
|
||||
return info
|
||||
}
|
||||
|
||||
@PostMapping(path = ["/update/url"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun updateUrl(
|
||||
@RequestBody info: UpdateUrl,
|
||||
@RequestHeader("token") token: String
|
||||
): Application {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
var application = applicationService.findApplicationById(user, info.id)
|
||||
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
if (application.unique_url != null) {
|
||||
throw BadRequest()
|
||||
}
|
||||
|
||||
application.original_url = application.url
|
||||
application.url = info.url
|
||||
application.unique_url = info.url.split("?")[0]
|
||||
|
||||
var maybe_exists =
|
||||
applicationService.findApplicationByUrl(
|
||||
user,
|
||||
application.url,
|
||||
application.unique_url
|
||||
)
|
||||
if (maybe_exists != null) {
|
||||
applicationService.delete(application)
|
||||
|
||||
if (maybe_exists.status == 0 && application.status == 1) {
|
||||
maybe_exists.status = 1
|
||||
applicationService.update(maybe_exists)
|
||||
}
|
||||
|
||||
maybe_exists.flairs = flairService.listFromLinkApplicationId(maybe_exists.id)
|
||||
|
||||
return maybe_exists
|
||||
}
|
||||
|
||||
applicationService.update(application)
|
||||
|
||||
application.flairs = flairService.listFromLinkApplicationId(application.id)
|
||||
|
||||
return application
|
||||
}
|
||||
|
||||
@PostMapping(path = ["/reset/url/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun updateUrl(
|
||||
@PathVariable id: String,
|
||||
@RequestHeader("token") token: String
|
||||
): Application {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
var application = applicationService.findApplicationById(user, id)
|
||||
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
if (application.unique_url == null) {
|
||||
throw BadRequest()
|
||||
}
|
||||
|
||||
application.url = application.original_url!!
|
||||
application.original_url = null
|
||||
application.unique_url = null
|
||||
|
||||
applicationService.update(application)
|
||||
|
||||
application.flairs = flairService.listFromLinkApplicationId(application.id)
|
||||
|
||||
return application
|
||||
}
|
||||
|
||||
@DeleteMapping(path = ["/flair/{id}/{flairid}"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun delete(
|
||||
@PathVariable id: String,
|
||||
@PathVariable flairid: String,
|
||||
@RequestHeader("token") token: String
|
||||
): Application {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
|
||||
val application = applicationService.findApplicationById(user, id)
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
flairService.unlinkFlair(id, flairid)
|
||||
return applicationService.findApplicationById(user, id)!!
|
||||
}
|
||||
|
||||
@DeleteMapping(path = ["/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun delete(
|
||||
@PathVariable id: String,
|
||||
@RequestHeader("token") token: String
|
||||
): Application {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
|
||||
val application = applicationService.findApplicationById(user, id)
|
||||
if (application == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
applicationService.delete(application)
|
||||
return application
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
class ApplicationService(val db: JdbcTemplate, val flairService: FlairService) {
|
||||
|
||||
public fun findApplicationByUrl(user: UserDb, url: String, unique_url: String?): Application? {
|
||||
if (unique_url != null) {
|
||||
val unique =
|
||||
db.query(
|
||||
"select * from applications where unique_url=? and user_id=?",
|
||||
arrayOf(unique_url, user.id),
|
||||
Application
|
||||
)
|
||||
.toList()
|
||||
|
||||
if (unique.size != 0) {
|
||||
return unique[0]
|
||||
}
|
||||
}
|
||||
|
||||
val applications =
|
||||
db.query(
|
||||
"select * from applications where url=? and user_id=?",
|
||||
arrayOf(url, user.id),
|
||||
Application
|
||||
)
|
||||
.toList()
|
||||
|
||||
if (applications.size == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return applications[0]
|
||||
}
|
||||
|
||||
public fun findApplicationById(user: UserDb, id: String): Application? {
|
||||
var applications =
|
||||
db.query(
|
||||
"select * from applications where id=? and user_id=?",
|
||||
arrayOf(id, user.id),
|
||||
Application
|
||||
)
|
||||
.toList()
|
||||
|
||||
if (applications.size == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
var application = applications[0]
|
||||
|
||||
application.flairs = flairService.listFromLinkApplicationId(application.id)
|
||||
|
||||
return application
|
||||
}
|
||||
|
||||
public fun createApplication(user: UserDb, application: Application): Boolean {
|
||||
if (this.findApplicationByUrl(user, application.url, application.unique_url) != null) {
|
||||
return false
|
||||
}
|
||||
|
||||
db.update(
|
||||
"insert into applications (id, url, original_url, unique_url, title, user_id, extra_data, payrange, status) values (?, ?, ?, ?, ?, ?, ?, ?, ?);",
|
||||
application.id,
|
||||
application.url,
|
||||
application.original_url,
|
||||
application.unique_url,
|
||||
application.title,
|
||||
application.user_id,
|
||||
application.extra_data,
|
||||
application.payrange,
|
||||
application.status,
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public fun findAll(user: UserDb, info: ListRequest): List<Application> {
|
||||
if (info.status == null) {
|
||||
return db.query(
|
||||
"select * from applications where user_id=? order by title asc;",
|
||||
arrayOf(user.id),
|
||||
Application
|
||||
)
|
||||
.toList()
|
||||
}
|
||||
|
||||
return db.query(
|
||||
"select * from applications where user_id=? and status=? order by title asc;",
|
||||
arrayOf(user.id, info.status),
|
||||
Application,
|
||||
)
|
||||
.toList()
|
||||
}
|
||||
|
||||
public fun update(application: Application): Application {
|
||||
db.update(
|
||||
"update applications set url=?, original_url=?, unique_url=?, title=?, user_id=?, extra_data=?, payrange=?, status=? where id=?",
|
||||
application.url,
|
||||
application.original_url,
|
||||
application.unique_url,
|
||||
application.title,
|
||||
application.user_id,
|
||||
application.extra_data,
|
||||
application.payrange,
|
||||
application.status,
|
||||
application.id,
|
||||
)
|
||||
return application
|
||||
}
|
||||
|
||||
public fun delete(application: Application) {
|
||||
db.update(
|
||||
"delete from applications where id=?",
|
||||
application.id,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.http.MediaType
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/utils")
|
||||
class BaseInfo {
|
||||
|
||||
@GetMapping(path = [ "/version" ], produces = [ MediaType.APPLICATION_JSON_VALUE ])
|
||||
fun version(): Version {
|
||||
return Version(1)
|
||||
}
|
||||
}
|
||||
|
||||
data class Version(val version: Int)
|
@ -0,0 +1,71 @@
|
||||
package com.andr3h3nriqu3s.appliations
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
||||
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer
|
||||
import org.springframework.web.servlet.mvc.Controller
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver
|
||||
import org.springframework.web.method.HandlerTypePredicate
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.servlet.ModelAndView
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
|
||||
import com.andr3h3nriqu3s.applications.NoToken
|
||||
import com.andr3h3nriqu3s.applications.NotAuth
|
||||
import com.andr3h3nriqu3s.applications.UserNotFound
|
||||
import com.andr3h3nriqu3s.applications.NotFound
|
||||
import com.andr3h3nriqu3s.applications.BadRequest
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
class WebConfig : WebMvcConfigurer {
|
||||
|
||||
override public fun configureContentNegotiation(configurer: ContentNegotiationConfigurer){
|
||||
// configurer.defaultContentType( MediaType.APPLICATION_JSON );
|
||||
configurer.mediaType("json", MediaType.APPLICATION_JSON)
|
||||
}
|
||||
|
||||
override public fun addCorsMappings(registry: CorsRegistry) {
|
||||
registry.addMapping("*").allowedOrigins("*")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
public class RestResponseStatusExceptionResolver : AbstractHandlerExceptionResolver() {
|
||||
|
||||
override protected fun doResolveException(
|
||||
requeset: HttpServletRequest,
|
||||
response: HttpServletResponse,
|
||||
handler: Any?,
|
||||
ex: Exception
|
||||
): ModelAndView? {
|
||||
try {
|
||||
if (ex is NoToken || ex is NotAuth || ex is UserNotFound) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN)
|
||||
return ModelAndView()
|
||||
}
|
||||
if (ex is NotFound) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
return ModelAndView()
|
||||
}
|
||||
if (ex is BadRequest) {
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST)
|
||||
return ModelAndView()
|
||||
}
|
||||
} catch (handlerException: Exception) {
|
||||
print("Faield to handle exception ")
|
||||
print(handlerException)
|
||||
print("\n")
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
public class NotAuth : Exception("Not Authenticated")
|
||||
public class NoToken : Exception("Invalid Token")
|
||||
public class UserNotFound : Exception("User Not Found")
|
||||
public class NotFound : Exception("Not Found")
|
||||
public class BadRequest : Exception("Bad Request")
|
209
api/src/main/kotlin/com/andr3h3nriqu3s/applications/Flair.kt
Normal file
209
api/src/main/kotlin/com/andr3h3nriqu3s/applications/Flair.kt
Normal file
@ -0,0 +1,209 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
import java.sql.ResultSet
|
||||
import java.util.UUID
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.jdbc.core.RowMapper
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.PutMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestHeader
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
data class CreateFlair(
|
||||
var color: String,
|
||||
var name: String,
|
||||
var expr: String,
|
||||
var description: String?
|
||||
)
|
||||
|
||||
@RestController
|
||||
@ControllerAdvice
|
||||
@RequestMapping("/api/flair")
|
||||
class FlairController(val sessionService: SessionService, val flairService: FlairService) {
|
||||
|
||||
@PutMapping(path = ["/"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun create(
|
||||
@RequestBody flair: CreateFlair,
|
||||
@RequestHeader("token") token: String
|
||||
): Flair {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
return flairService.createFlair(user, flair)
|
||||
}
|
||||
|
||||
@PutMapping(path = ["/update"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun create(@RequestBody flair: Flair, @RequestHeader("token") token: String): Flair {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
|
||||
var old_flair = flairService.getById(user, flair.id)
|
||||
if (old_flair == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
if (old_flair.user_id != user.id) {
|
||||
throw NotAuth()
|
||||
}
|
||||
|
||||
flair.user_id = old_flair.user_id
|
||||
|
||||
return flairService.updateFlair(flair)
|
||||
}
|
||||
|
||||
@GetMapping(path = ["/"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun list(@RequestHeader("token") token: String): List<Flair> {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
return flairService.listUser(user)
|
||||
}
|
||||
|
||||
@DeleteMapping(path = ["/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun delete(@PathVariable id: String, @RequestHeader("token") token: String): Flair {
|
||||
val user = sessionService.verifyTokenThrow(token)
|
||||
return flairService.deleteById(user, id)
|
||||
}
|
||||
}
|
||||
|
||||
data class Flair(
|
||||
var id: String,
|
||||
var user_id: String,
|
||||
var color: String,
|
||||
var name: String,
|
||||
var expr: String,
|
||||
var description: String,
|
||||
) {
|
||||
companion object : RowMapper<Flair> {
|
||||
override public fun mapRow(rs: ResultSet, rowNum: Int): Flair {
|
||||
return Flair(
|
||||
rs.getString("id"),
|
||||
rs.getString("user_id"),
|
||||
rs.getString("color"),
|
||||
rs.getString("name"),
|
||||
rs.getString("expr"),
|
||||
rs.getString("description"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class FlairLink(var id: String, var application_id: String, var flair_id: String)
|
||||
|
||||
@Service
|
||||
public class FlairService(val db: JdbcTemplate) {
|
||||
|
||||
public fun linkFlair(application: Application, flair: Flair): FlairLink {
|
||||
val links =
|
||||
db.query(
|
||||
"select * from flair_link where application_id=? and flair_id=?",
|
||||
arrayOf(application.id, flair.id)
|
||||
) { request, _ ->
|
||||
FlairLink(
|
||||
request.getString("id"),
|
||||
request.getString("application_id"),
|
||||
request.getString("flair_id")
|
||||
)
|
||||
}
|
||||
|
||||
if (links.size > 0) {
|
||||
return links[0]
|
||||
}
|
||||
|
||||
val link = FlairLink(UUID.randomUUID().toString(), application.id, flair.id)
|
||||
|
||||
db.update(
|
||||
"insert into flair_link (id, application_id, flair_id) values (?, ?, ?)",
|
||||
link.id,
|
||||
link.application_id,
|
||||
link.flair_id
|
||||
)
|
||||
|
||||
return link
|
||||
}
|
||||
|
||||
public fun unlinkFlair(applicationId: String, flairId: String) {
|
||||
db.update(
|
||||
"delete from flair_link where flair_id=? and application_id=?",
|
||||
flairId,
|
||||
applicationId,
|
||||
)
|
||||
}
|
||||
|
||||
public fun listFromLinkApplicationId(id: String): List<Flair> =
|
||||
db.query(
|
||||
"select f.id, f.user_id, f.color, f.name, f.expr, f.description from flair_link as fl inner join flair as f on f.id = fl.flair_id where application_id=?;",
|
||||
arrayOf(id),
|
||||
Flair
|
||||
)
|
||||
.toList()
|
||||
|
||||
public fun listUser(user: UserDb): List<Flair> =
|
||||
db.query("select * from flair where user_id=?;", arrayOf(user.id), Flair).toList()
|
||||
|
||||
public fun getById(user: UserDb, id: String): Flair? {
|
||||
val items =
|
||||
db.query(
|
||||
"select * from flair where user_id=? and id=?;",
|
||||
arrayOf(user.id, id),
|
||||
Flair
|
||||
)
|
||||
.toList()
|
||||
|
||||
if (items.size == 0) {
|
||||
return null
|
||||
}
|
||||
return items[0]
|
||||
}
|
||||
|
||||
public fun deleteById(user: UserDb, id: String): Flair {
|
||||
val flair = this.getById(user, id)
|
||||
if (flair == null) {
|
||||
throw NotFound()
|
||||
}
|
||||
|
||||
db.update("delete from flair where id=?", id)
|
||||
|
||||
return flair
|
||||
}
|
||||
|
||||
public fun updateFlair(flair: Flair): Flair {
|
||||
db.update(
|
||||
"update flair set user_id=?, color=?, name=?, expr=?, description=? where id=?;",
|
||||
flair.user_id,
|
||||
flair.color,
|
||||
flair.name,
|
||||
flair.expr,
|
||||
flair.description,
|
||||
flair.id,
|
||||
)
|
||||
|
||||
return flair
|
||||
}
|
||||
|
||||
public fun createFlair(user: UserDb, flair: CreateFlair): Flair {
|
||||
val id = UUID.randomUUID().toString()
|
||||
|
||||
var description = ""
|
||||
|
||||
if (flair.description != null) {
|
||||
description = flair.description!!
|
||||
}
|
||||
|
||||
var new_flair = Flair(id, user.id, flair.color, flair.name, flair.expr, description)
|
||||
|
||||
db.update(
|
||||
"insert into flair (id, user_id, color, name, expr, description) values (?, ?, ?, ?, ?, ?)",
|
||||
new_flair.id,
|
||||
new_flair.user_id,
|
||||
new_flair.color,
|
||||
new_flair.name,
|
||||
new_flair.expr,
|
||||
new_flair.description
|
||||
)
|
||||
|
||||
return new_flair
|
||||
}
|
||||
}
|
225
api/src/main/kotlin/com/andr3h3nriqu3s/applications/User.kt
Normal file
225
api/src/main/kotlin/com/andr3h3nriqu3s/applications/User.kt
Normal file
@ -0,0 +1,225 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
import java.util.UUID
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.random.Random
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestHeader
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
enum class UserLevel(val level: Int) {
|
||||
NORMAL(1),
|
||||
ADMIN(255)
|
||||
}
|
||||
|
||||
data class UserDb(
|
||||
var id: String,
|
||||
var username: String,
|
||||
var email: String,
|
||||
var password: String,
|
||||
var level: Int
|
||||
) {
|
||||
fun toSafe(): User {
|
||||
return User(this.id, this.username, this.email, this.level)
|
||||
}
|
||||
|
||||
fun checkLevel(level: Int): Boolean {
|
||||
return (level and this.level) == level
|
||||
}
|
||||
|
||||
fun checkLevelThrow(level: Int) {
|
||||
if (!this.checkLevel(level)) {
|
||||
throw NotAuth()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class UserCreateRequest(val email: String, val password: String, val username: String)
|
||||
|
||||
data class LoginUserRequest(val email: String, val password: String)
|
||||
|
||||
data class LoggedInUser(val token: String, val user: User)
|
||||
|
||||
data class User(val id: String, var username: String, var email: String, var level: Int)
|
||||
|
||||
@RestController
|
||||
@ControllerAdvice
|
||||
@RequestMapping("/api/user")
|
||||
@kotlin.io.encoding.ExperimentalEncodingApi
|
||||
class UserController(
|
||||
val userService: UserService,
|
||||
val sessionService: SessionService,
|
||||
val sessionServiceCreator: SessionServiceCreator,
|
||||
) {
|
||||
|
||||
@PostMapping(path = ["/login"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun login(@RequestBody user: LoginUserRequest): LoggedInUser {
|
||||
val userdb = userService.login(user.email, user.password)
|
||||
val session = sessionServiceCreator.createSession(userdb)
|
||||
|
||||
return LoggedInUser(session.token, userdb.toSafe())
|
||||
}
|
||||
|
||||
@GetMapping(path = ["/list"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun list(@RequestHeader("token") token: String): List<User> {
|
||||
sessionService.verifyTokenThrow(token).checkLevelThrow(UserLevel.ADMIN.ordinal)
|
||||
return userService.findUsers().map { elm -> elm.toSafe() }
|
||||
}
|
||||
|
||||
@PostMapping(path = ["/register"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
public fun register(@RequestBody user: UserCreateRequest): LoggedInUser {
|
||||
var new_user = userService.createUser(user)
|
||||
val session = sessionServiceCreator.createSession(new_user)
|
||||
|
||||
return LoggedInUser(session.token, new_user.toSafe())
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
class UserService(val db: JdbcTemplate) {
|
||||
|
||||
fun login(email: String, passwd: String): UserDb {
|
||||
var user = this.findUserByEmail(email)
|
||||
if (user == null) {
|
||||
throw UserNotFound()
|
||||
}
|
||||
|
||||
var arg2SpringSecurity = Argon2PasswordEncoder(16, 32, 1, 60000, 10)
|
||||
|
||||
// TODO make this safe
|
||||
if (!arg2SpringSecurity.matches(passwd, user.password)) {
|
||||
throw UserNotFound()
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
fun findUserByEmail(email: String): UserDb? {
|
||||
var users =
|
||||
db
|
||||
.query("select * from users where email=?", arrayOf(email)) { response, _ ->
|
||||
UserDb(
|
||||
response.getString("id"),
|
||||
response.getString("username"),
|
||||
response.getString("email"),
|
||||
response.getString("passwd"),
|
||||
response.getInt("level")
|
||||
)
|
||||
}
|
||||
.toList()
|
||||
|
||||
if (users.size == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return users[0]
|
||||
}
|
||||
|
||||
fun createUser(user: UserCreateRequest): UserDb {
|
||||
var user_check = findUserByEmail(user.email)
|
||||
if (user_check != null) {
|
||||
throw Exception("User already exists")
|
||||
}
|
||||
|
||||
val id = UUID.randomUUID().toString()
|
||||
|
||||
var arg2SpringSecurity = Argon2PasswordEncoder(16, 32, 1, 60000, 10)
|
||||
val hashPassword = arg2SpringSecurity.encode(user.password)
|
||||
|
||||
var new_user = UserDb(id, user.username, user.email, hashPassword, UserLevel.NORMAL.ordinal)
|
||||
|
||||
db.update(
|
||||
"insert into users (id, username, email, passwd, level) values (?, ?, ?, ?, ?)",
|
||||
new_user.id,
|
||||
user.username,
|
||||
user.email,
|
||||
new_user.password,
|
||||
new_user.level,
|
||||
)
|
||||
|
||||
return new_user
|
||||
}
|
||||
|
||||
fun findUsers(): List<UserDb> =
|
||||
db.query("select * from users") { response, _ ->
|
||||
UserDb(
|
||||
response.getString("id"),
|
||||
response.getString("username"),
|
||||
response.getString("email"),
|
||||
response.getString("passwd"),
|
||||
response.getInt("level"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class Session(val token: String, val user_id: String)
|
||||
|
||||
@Service
|
||||
class SessionService(val db: JdbcTemplate) {
|
||||
|
||||
fun verifyToken(token: String): UserDb? {
|
||||
var users =
|
||||
db
|
||||
.query(
|
||||
"select * from tokens as t inner join users as u on id = user_id where token = ?",
|
||||
arrayOf(token)
|
||||
) { response, _ ->
|
||||
UserDb(
|
||||
response.getString("id"),
|
||||
response.getString("username"),
|
||||
response.getString("email"),
|
||||
response.getString("passwd"),
|
||||
response.getInt("level"),
|
||||
)
|
||||
}
|
||||
.toList()
|
||||
|
||||
if (users.size == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return users[0]
|
||||
}
|
||||
|
||||
fun verifyTokenThrow(token: String): UserDb {
|
||||
val new_user = this.verifyToken(token)
|
||||
if (new_user == null) {
|
||||
throw NoToken()
|
||||
}
|
||||
return new_user
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
@kotlin.io.encoding.ExperimentalEncodingApi
|
||||
class SessionServiceCreator(val db: JdbcTemplate) {
|
||||
|
||||
fun createSession(user: UserDb): Session {
|
||||
val session = Session(this.generateToken(), user.id)
|
||||
|
||||
db.update(
|
||||
"insert into tokens (token, user_id) values (?,?);",
|
||||
session.token,
|
||||
session.user_id
|
||||
)
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
fun generateToken(): String {
|
||||
var b = ByteArray(60)
|
||||
Random.nextBytes(b)
|
||||
|
||||
return Base64.encode(b)
|
||||
}
|
||||
}
|
1
api/src/main/resources/application.properties
Normal file
1
api/src/main/resources/application.properties
Normal file
@ -0,0 +1 @@
|
||||
spring.application.name=Applications
|
38
api/src/main/resources/schema.sql
Normal file
38
api/src/main/resources/schema.sql
Normal file
@ -0,0 +1,38 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id VARCHAR PRIMARY KEY,
|
||||
username VARCHAR NOT NULL,
|
||||
email VARCHAR NOT NULL,
|
||||
passwd VARCHAR NOT NULL,
|
||||
level INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tokens (
|
||||
token VARCHAR PRIMARY KEY,
|
||||
user_id VARCHAR
|
||||
);
|
||||
|
||||
create table if not exists applications (
|
||||
id text primary key,
|
||||
url text not null,
|
||||
original_url text,
|
||||
unique_url text,
|
||||
title text,
|
||||
user_id text,
|
||||
extra_data text,
|
||||
status integer
|
||||
);
|
||||
|
||||
create table if not exists flair (
|
||||
id text primary key,
|
||||
user_id text not null,
|
||||
color text default '#ff0000',
|
||||
name text default 'New Flair',
|
||||
expr text default 'flair'
|
||||
description text default '',
|
||||
);
|
||||
|
||||
create table if not exists flair_link (
|
||||
id text primary key,
|
||||
application_id text not null,
|
||||
flair_id text not null
|
||||
);
|
@ -0,0 +1,13 @@
|
||||
package com.andr3h3nriqu3s.applications
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
|
||||
@SpringBootTest
|
||||
class ApplicationsApplicationTests {
|
||||
|
||||
@Test
|
||||
fun contextLoads() {
|
||||
}
|
||||
|
||||
}
|
0
api/test.db
Normal file
0
api/test.db
Normal file
66
extensions/background-script.js
Normal file
66
extensions/background-script.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*browser.browserAction.onClicked.addListener(function (e) {
|
||||
console.log("This is a nice test!", e);
|
||||
});*/
|
||||
|
||||
browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
|
||||
if (message.type !== "MY_GET_URL") return;
|
||||
|
||||
let windowList = (await browser.storage.local.get("windows")).windows ?? [];
|
||||
if (windowList.length !== 1) {
|
||||
browser.tabs.sendMessage(sender.tab.id, {
|
||||
type: "MY_GET_URL_R",
|
||||
error: "Invalid number of pages marked as target",
|
||||
data: windowList,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const tab = await browser.tabs.get(windowList[0]);
|
||||
|
||||
browser.tabs.sendMessage(sender.tab.id, {
|
||||
type: "MY_GET_URL_R",
|
||||
url: tab.url,
|
||||
all_data: tab,
|
||||
});
|
||||
});
|
||||
|
||||
browser.runtime.onInstalled.addListener(async () => {
|
||||
console.log(browser);
|
||||
|
||||
await browser.storage.local.set({
|
||||
windows: [],
|
||||
});
|
||||
|
||||
// Clear the menus from the prev install
|
||||
browser.menus.removeAll();
|
||||
browser.menus.create({
|
||||
id: "mark-page",
|
||||
title: "Mark Page As the Glassdoor target",
|
||||
contexts: ["all"],
|
||||
});
|
||||
|
||||
browser.menus.create({
|
||||
id: "mark-page-clear",
|
||||
title: "Clear Marked Pages",
|
||||
contexts: ["all"],
|
||||
});
|
||||
|
||||
browser.menus.onClicked.addListener(async function (e, tab) {
|
||||
let windowList =
|
||||
(await browser.storage.local.get("windows")).windows ?? [];
|
||||
if (e.menuItemId === "mark-page") {
|
||||
console.log("marking page", tab);
|
||||
if (windowList.includes(tab.id)) {
|
||||
windowList = windowList.filter((a) => a !== tab.id);
|
||||
} else {
|
||||
windowList.push(tab.id);
|
||||
}
|
||||
} else if (e.menuItemId === "mark-page-clear") {
|
||||
windowList = [];
|
||||
console.log("clear");
|
||||
}
|
||||
await browser.storage.local.set({
|
||||
windows: windowList,
|
||||
});
|
||||
});
|
||||
});
|
15
extensions/definitions.js
Normal file
15
extensions/definitions.js
Normal file
@ -0,0 +1,15 @@
|
||||
browser.runtime.onMessage.addListener(function (message) {
|
||||
if (message.type === "MY_GET_URL_R") {
|
||||
window.postMessage(message);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("message", function (e) {
|
||||
if (e.data.type === "MY_GET_URL") {
|
||||
browser.runtime.sendMessage({ type: "MY_GET_URL" });
|
||||
} else if (e.data.type === "HAS_EXTENSION_Q") {
|
||||
console.log("Got request for ext");
|
||||
window.postMessage({ type: "HAS_EXTENSION" });
|
||||
}
|
||||
//console.log("here2", e);
|
||||
});
|
29
extensions/manifest.json
Normal file
29
extensions/manifest.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Url Extractor Extension",
|
||||
"version": "1.0",
|
||||
|
||||
"description": "Allow my webpage to extract urls from other webpages",
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["definitions.js"],
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
|
||||
"permissions": ["activeTab", "menus", "tabs", "storage"],
|
||||
|
||||
"background": {
|
||||
"scripts": ["background-script.js"],
|
||||
"persistent": false,
|
||||
"type": "module"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "me@andr3h3nriqu3s.com"
|
||||
}
|
||||
}
|
||||
}
|
49
nginx.proxy.conf
Normal file
49
nginx.proxy.conf
Normal file
@ -0,0 +1,49 @@
|
||||
events {
|
||||
worker_connections 2024;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
proxy_read_timeout 600;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 8001;
|
||||
|
||||
client_max_body_size 5G;
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass http://localhost:5173;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
}
|
||||
|
||||
location /api {
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
}
|
||||
|
||||
location /glassdoor {
|
||||
|
||||
rewrite ^/glassdoor(.*)$ $1 break;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass https://glassdoor.com;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
}
|
||||
}
|
||||
}
|
21
site/.gitignore
vendored
Normal file
21
site/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
1
site/.npmrc
Normal file
1
site/.npmrc
Normal file
@ -0,0 +1 @@
|
||||
engine-strict=true
|
4
site/.prettierignore
Normal file
4
site/.prettierignore
Normal file
@ -0,0 +1,4 @@
|
||||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
8
site/.prettierrc
Normal file
8
site/.prettierrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
}
|
38
site/README.md
Normal file
38
site/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
33
site/eslint.config.js
Normal file
33
site/eslint.config.js
Normal file
@ -0,0 +1,33 @@
|
||||
import js from '@eslint/js';
|
||||
import ts from 'typescript-eslint';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import prettier from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
|
||||
/** @type {import('eslint').Linter.FlatConfig[]} */
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
...ts.configs.recommended,
|
||||
...svelte.configs['flat/recommended'],
|
||||
prettier,
|
||||
...svelte.configs['flat/prettier'],
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.svelte'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: ts.parser
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: ['build/', '.svelte-kit/', 'dist/']
|
||||
}
|
||||
];
|
4654
site/package-lock.json
generated
Normal file
4654
site/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
36
site/package.json
Normal file
36
site/package.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "site",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/eslint": "^8.56.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.36.0",
|
||||
"globals": "^15.0.0",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^5.0.0-next.1",
|
||||
"svelte-check": "^3.6.0",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.0.0-alpha.20",
|
||||
"vite": "^5.0.3"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
2541
site/pnpm-lock.yaml
Normal file
2541
site/pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
6
site/postcss.config.js
Normal file
6
site/postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
74
site/src/app.css
Normal file
74
site/src/app.css
Normal file
@ -0,0 +1,74 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrainsMono';
|
||||
src: url('/fonts/JetBrainsMono-VariableFont_wght.ttf');
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.grad-back {
|
||||
@apply bg-gradient-to-t from-violet-700 via-blue-400 to-violet-700;
|
||||
background-size: 100vw 400vh;
|
||||
animation: grad-back 100s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes grad-back {
|
||||
from {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
to {
|
||||
background-position: 0 400vh;
|
||||
}
|
||||
}
|
||||
|
||||
.font-JetBrainsMono {
|
||||
font-family: 'JetBrainsMono';
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-purple-500 font-bold font-JetBrainsMono text-xl;
|
||||
}
|
||||
|
||||
dialog {
|
||||
@apply p-3 rounded-md;
|
||||
}
|
||||
|
||||
dialog::backdrop {
|
||||
@apply bg-secudanry opacity-75 fixed top-0 right-0 bottom-0 left-0;
|
||||
}
|
||||
|
||||
.flabel {
|
||||
@apply block text-purple-500;
|
||||
}
|
||||
|
||||
.finput {
|
||||
@apply rounded-lg w-full p-2 drop-shadow-lg border-gray-300 border;
|
||||
}
|
||||
|
||||
.finput[type='color'] {
|
||||
@apply p-0;
|
||||
}
|
||||
|
||||
.btns {
|
||||
@apply flex justify-center py-2 gap-2;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply rounded-lg text-white bg-violet-500 p-2;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
@apply rounded-lg bg-danger p-2 text-white;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
@apply rounded-lg bg-blue-400 text-white p-2;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-lg drop-shadow-lg;
|
||||
}
|
||||
}
|
13
site/src/app.d.ts
vendored
Normal file
13
site/src/app.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
18
site/src/app.html
Normal file
18
site/src/app.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
|
||||
/>
|
||||
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body class="grad-back" data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
91
site/src/lib/ApplicationsStore.svelte.ts
Normal file
91
site/src/lib/ApplicationsStore.svelte.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import type { Flair } from './FlairStore.svelte';
|
||||
import { post } from './utils';
|
||||
|
||||
export const ApplicationStatus = Object.freeze({
|
||||
ToApply: 0,
|
||||
WorkingOnIt: 1,
|
||||
Ignore: 2,
|
||||
ApplyedButSaidNo: 3,
|
||||
Applyed: 4,
|
||||
Expired: 5
|
||||
});
|
||||
|
||||
export const ApplicationStatusMaping: Record<
|
||||
(typeof ApplicationStatus)[keyof typeof ApplicationStatus],
|
||||
string
|
||||
> = Object.freeze({
|
||||
0: 'To Apply',
|
||||
1: 'Working On It',
|
||||
2: 'Ignore',
|
||||
3: 'Applyed But Said No',
|
||||
4: 'Applyed',
|
||||
5: 'Expired'
|
||||
});
|
||||
|
||||
export type Application = {
|
||||
id: string;
|
||||
url: string;
|
||||
original_url: string | null;
|
||||
unique_url: string | null;
|
||||
title: string;
|
||||
user_id: string;
|
||||
extra_data: string;
|
||||
payrange: string;
|
||||
status: number;
|
||||
flairs: Flair[];
|
||||
};
|
||||
|
||||
function createApplicationStore() {
|
||||
let applications: Application[] = $state([]);
|
||||
let applyed: Application[] = $state([]);
|
||||
|
||||
let dragApplication: Application | undefined = $state(undefined);
|
||||
|
||||
return {
|
||||
/**
|
||||
* @throws {Error}
|
||||
*/
|
||||
async loadApplications(force = false) {
|
||||
if (!force && applications.length > 1) {
|
||||
return;
|
||||
}
|
||||
applications = await post('application/list', { status: 0 });
|
||||
},
|
||||
|
||||
/**
|
||||
* @throws {Error}
|
||||
*/
|
||||
async loadAplyed(force = false) {
|
||||
if (!force && applications.length > 1) {
|
||||
return;
|
||||
}
|
||||
applyed = await post('application/list', { status: ApplicationStatus.Applyed });
|
||||
},
|
||||
|
||||
clear() {
|
||||
applications = [];
|
||||
},
|
||||
|
||||
dragStart(application: Application) {
|
||||
dragApplication = application;
|
||||
},
|
||||
|
||||
dragEnd() {
|
||||
dragApplication = undefined;
|
||||
},
|
||||
|
||||
get dragging() {
|
||||
return dragApplication;
|
||||
},
|
||||
|
||||
get applications() {
|
||||
return applications;
|
||||
},
|
||||
|
||||
get applyed() {
|
||||
return applyed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const applicationStore = createApplicationStore();
|
29
site/src/lib/FlairStore.svelte.ts
Normal file
29
site/src/lib/FlairStore.svelte.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { get } from './utils';
|
||||
|
||||
export type Flair = {
|
||||
id: string;
|
||||
user_id: string;
|
||||
color: string;
|
||||
name: string;
|
||||
expr: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
function createFlairStore() {
|
||||
let flairList: Flair[] = $state([]);
|
||||
|
||||
return {
|
||||
get flairs() {
|
||||
return flairList;
|
||||
},
|
||||
|
||||
async loadItems(force?: boolean) {
|
||||
if (flairList.length > 0 && !force) {
|
||||
return;
|
||||
}
|
||||
flairList = await get('flair/');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const flairStore = createFlairStore();
|
16
site/src/lib/HasUser.svelte
Normal file
16
site/src/lib/HasUser.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { onMount, type Snippet } from 'svelte';
|
||||
import { userStore } from './UserStore.svelte';
|
||||
|
||||
let ready = $state(false);
|
||||
|
||||
const { children }: { children: Snippet } = $props();
|
||||
|
||||
onMount(() => {
|
||||
ready = userStore.checkLogin();
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if ready}
|
||||
{@render children()}
|
||||
{/if}
|
72
site/src/lib/UserStore.svelte.ts
Normal file
72
site/src/lib/UserStore.svelte.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export type User = {
|
||||
token: string;
|
||||
user: {
|
||||
username: string;
|
||||
email: string;
|
||||
level: number;
|
||||
};
|
||||
};
|
||||
|
||||
function createUserStore() {
|
||||
let user: User | undefined = $state();
|
||||
|
||||
const local_user = localStorage.getItem('user');
|
||||
if (local_user) {
|
||||
try {
|
||||
user = JSON.parse(local_user);
|
||||
} catch {
|
||||
localStorage.removeItem('user');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
checkLogin(redirect = true) {
|
||||
console.log('test1');
|
||||
if (user !== undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log('test2');
|
||||
if (redirect) {
|
||||
goto('/login');
|
||||
}
|
||||
|
||||
console.log('test3');
|
||||
return false;
|
||||
},
|
||||
|
||||
get isLoggedIn() {
|
||||
console.log(user);
|
||||
return user !== undefined;
|
||||
},
|
||||
|
||||
get token() {
|
||||
if (user === undefined) {
|
||||
throw new Error('User not logged in');
|
||||
}
|
||||
|
||||
return user.token;
|
||||
},
|
||||
|
||||
set user(new_user: User | undefined) {
|
||||
user = new_user;
|
||||
if (new_user === undefined) {
|
||||
localStorage.removeItem('user');
|
||||
} else {
|
||||
localStorage.setItem('user', JSON.stringify(new_user));
|
||||
}
|
||||
},
|
||||
|
||||
get user(): User['user'] {
|
||||
if (user === undefined) {
|
||||
throw new Error('User not logged in');
|
||||
}
|
||||
|
||||
return user.user;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const userStore = createUserStore();
|
1
site/src/lib/index.ts
Normal file
1
site/src/lib/index.ts
Normal file
@ -0,0 +1 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
60
site/src/lib/utils.ts
Normal file
60
site/src/lib/utils.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { userStore } from './UserStore.svelte';
|
||||
|
||||
export function preventDefault<T extends Event, Return>(f: (e: T) => Return): (e: T) => Return {
|
||||
return (e: T): Return => {
|
||||
e.preventDefault();
|
||||
return f(e);
|
||||
};
|
||||
}
|
||||
|
||||
export async function request(
|
||||
method: 'POST' | 'PUT' | 'GET' | 'DELETE',
|
||||
url: string,
|
||||
body?: unknown
|
||||
) {
|
||||
const headers = new Headers();
|
||||
headers.append('response-type', 'application/json');
|
||||
|
||||
if (body) {
|
||||
headers.append('content-type', 'application/json');
|
||||
}
|
||||
|
||||
if (userStore.isLoggedIn) {
|
||||
headers.append('token', userStore.token);
|
||||
}
|
||||
|
||||
const r = await fetch(`/api/${url}`, {
|
||||
method,
|
||||
headers,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
if (r.status === 401) {
|
||||
userStore.user = undefined;
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
if (r.status !== 200) {
|
||||
throw r;
|
||||
}
|
||||
|
||||
return r.json();
|
||||
}
|
||||
|
||||
export async function get(url: string) {
|
||||
return request('GET', url);
|
||||
}
|
||||
|
||||
export async function deleteR(url: string) {
|
||||
return request('DELETE', url);
|
||||
}
|
||||
|
||||
export async function post(url: string, body: unknown) {
|
||||
return request('POST', url, body);
|
||||
}
|
||||
|
||||
export async function put(url: string, body: unknown) {
|
||||
return request('PUT', url, body);
|
||||
}
|
5
site/src/routes/+layout.svelte
Normal file
5
site/src/routes/+layout.svelte
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
import '../app.css';
|
||||
</script>
|
||||
|
||||
<slot />
|
4
site/src/routes/+layout.ts
Normal file
4
site/src/routes/+layout.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const prerender = true;
|
||||
export const ssr = false;
|
||||
export const csr = true;
|
||||
export const trailingSlash = 'always';
|
20
site/src/routes/+page.svelte
Normal file
20
site/src/routes/+page.svelte
Normal file
@ -0,0 +1,20 @@
|
||||
<script lang="ts">
|
||||
import NavBar from './NavBar.svelte';
|
||||
import HasUser from '$lib/HasUser.svelte';
|
||||
import ApplicationsList from './ApplicationsList.svelte';
|
||||
import WorkArea from './work-area/WorkArea.svelte';
|
||||
import AppliyedList from './AppliyedList.svelte';
|
||||
</script>
|
||||
|
||||
<HasUser>
|
||||
<div class="flex flex-col h-[100vh]">
|
||||
<NavBar />
|
||||
<div class="w-full px-4 grow h-full gap-3 flex flex-col">
|
||||
<div class="flex h-3/5 gap-3">
|
||||
<ApplicationsList />
|
||||
<WorkArea />
|
||||
</div>
|
||||
<AppliyedList />
|
||||
</div>
|
||||
</div>
|
||||
</HasUser>
|
50
site/src/routes/ApplicationsList.svelte
Normal file
50
site/src/routes/ApplicationsList.svelte
Normal file
@ -0,0 +1,50 @@
|
||||
<script lang="ts">
|
||||
import { applicationStore } from '$lib/ApplicationsStore.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let filter = $state('');
|
||||
|
||||
onMount(() => {
|
||||
applicationStore.loadApplications();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="w-2/12 card p-3 flex flex-col">
|
||||
<h1>To Apply</h1>
|
||||
<div class="flex">
|
||||
<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
|
||||
<div>
|
||||
{applicationStore.applications.length}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-auto flex-grow p-2">
|
||||
{#each applicationStore.applications.filter((i) => {
|
||||
if (!filter) {
|
||||
return true;
|
||||
}
|
||||
const f = new RegExp(filter, 'ig');
|
||||
return i.title.match(f);
|
||||
}) as item}
|
||||
<div
|
||||
class="card p-2 my-2 bg-slate-100"
|
||||
draggable="true"
|
||||
ondragstart={() => applicationStore.dragStart(item)}
|
||||
ondragend={() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
applicationStore.dragEnd();
|
||||
});
|
||||
}}
|
||||
role="none"
|
||||
>
|
||||
<div class:animate-pulse={applicationStore.dragging?.id === item.id}>
|
||||
<h2 class="text-lg text-blue-500">
|
||||
{item.title}
|
||||
</h2>
|
||||
<a href={item.url} class="text-violet-600 overflow-hidden whitespace-nowrap block">
|
||||
{item.url}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
36
site/src/routes/AppliyedList.svelte
Normal file
36
site/src/routes/AppliyedList.svelte
Normal file
@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { applicationStore } from '$lib/ApplicationsStore.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
onMount(() => {
|
||||
applicationStore.loadAplyed();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="card p-3 rounded-lg flex flex-col">
|
||||
<h1>Applied</h1>
|
||||
<div class="overflow-auto flex-grow">
|
||||
{#each applicationStore.applyed as item}
|
||||
<div
|
||||
class="card p-2 my-2 bg-slate-100"
|
||||
draggable="true"
|
||||
ondragstart={() => applicationStore.dragStart(item)}
|
||||
ondragend={() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
applicationStore.dragEnd();
|
||||
});
|
||||
}}
|
||||
role="none"
|
||||
>
|
||||
<div class:animate-pulse={applicationStore.dragging?.id === item.id}>
|
||||
<h2 class="text-lg text-blue-500">
|
||||
{item.title}
|
||||
</h2>
|
||||
<a href={item.url} class="text-violet-600 overflow-hidden whitespace-nowrap block">
|
||||
{item.url}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
29
site/src/routes/NavBar.svelte
Normal file
29
site/src/routes/NavBar.svelte
Normal file
@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { userStore } from '$lib/UserStore.svelte';
|
||||
</script>
|
||||
|
||||
<div class="p-7">
|
||||
<div class="card p-2 rounded-xl flex">
|
||||
<button class="text-secudanry hover:text-primary px-2" onclick={() => goto('/')}> Home </button>
|
||||
<button class="text-secudanry hover:text-primary px-2" onclick={() => goto('/submit')}>
|
||||
Submit text
|
||||
</button>
|
||||
<button class="text-secudanry hover:text-primary px-2" onclick={() => goto('/flair')}>
|
||||
Flair
|
||||
</button>
|
||||
<div class="flex-grow"></div>
|
||||
<div class="text-secudanry px-2">
|
||||
{userStore.user.username}
|
||||
</div>
|
||||
<button
|
||||
class="text-secudanry hover:text-primary px-2"
|
||||
onclick={() => {
|
||||
userStore.user = undefined;
|
||||
goto('/login');
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
132
site/src/routes/cv/+page.svelte
Normal file
132
site/src/routes/cv/+page.svelte
Normal file
@ -0,0 +1,132 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let id: string | undefined | null;
|
||||
|
||||
onMount(() => {
|
||||
const url = new URLSearchParams(window.location.search);
|
||||
|
||||
id = url.get('id');
|
||||
|
||||
loadData();
|
||||
});
|
||||
|
||||
const application = undefined;
|
||||
|
||||
async function loadData() {}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>CV</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="flex items-center w-full flex-col">
|
||||
<div class="max-w-[210mm] px-5 py-16">
|
||||
<div class="w-full flex">
|
||||
<h1 class="dark:text-white text-black text-5xl">Andre Henriques</h1>
|
||||
<div class="flex-grow"></div>
|
||||
<div class="text-right">
|
||||
<ul>
|
||||
<li class="px-1">
|
||||
<a class="text-white underline" href="mailto:contact@andr3h3nriqu3s.com"
|
||||
>contact@andr3h3nriqu3s.com</a
|
||||
>
|
||||
</li>
|
||||
<li class="px-1">
|
||||
<a class="text-white underline" href="tel:+4407823391342">+44 0 782339 1342</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-5"></div>
|
||||
<div class="w-full flex py-10">
|
||||
<div class="text-white">
|
||||
I am a dedicated and versatile programmer with for year of professional experience. <br />
|
||||
During those years mainly worked with Typescript, JavaScript, React, Svelte. <br />
|
||||
I thrive in high paced new environments, and I am always striving to learn new skills and technologies.
|
||||
<br />
|
||||
I also am knowable in various other technologies and am always learning new ones. <br />
|
||||
</div>
|
||||
</div>
|
||||
{#if application}
|
||||
<div class="p-5"></div>
|
||||
<div>TODO: Application Information</div>
|
||||
{/if}
|
||||
<div class="p-5"></div>
|
||||
<div class="dark:text-white text-black">
|
||||
<h2 class="py-2 text-3xl">Work Expericence</h2>
|
||||
<div>
|
||||
<div>
|
||||
<h1>Planum Solucoes, Lda</h1>
|
||||
<div class="ml-5">
|
||||
<h2>4 year - May 2020 - Present</h2>
|
||||
<h3>Working with:</h3>
|
||||
<ul class="pl-5 list-disc">
|
||||
<li>Python</li>
|
||||
<li>Jenkins</li>
|
||||
<li>GitLab CI</li>
|
||||
<li>Ansible</li>
|
||||
<li>Docker</li>
|
||||
</ul>
|
||||
<h3>Associated Software Developer / DevOps Engineer:</h3>
|
||||
<ul class="pl-5 list-disc">
|
||||
<li>Developed web-based tools for the DevOps team to use</li>
|
||||
<li>
|
||||
Updated Jenkins pipelines that the team uses to manage one of the most important
|
||||
pipelines that the team manages.
|
||||
</li>
|
||||
<li>
|
||||
Created new scripts that were used to clean up multiple terabytes of unused data
|
||||
that led to improvements in the performance of the other scripts running on the same
|
||||
server as well as the performance of the backup system
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Sky UK</h1>
|
||||
<div class="ml-5">
|
||||
<h2>1 year - July 2022 - June 2023</h2>
|
||||
<h3>Working with:</h3>
|
||||
<ul class="pl-5 list-disc">
|
||||
<li>Python</li>
|
||||
<li>Jenkins</li>
|
||||
<li>GitLab CI</li>
|
||||
<li>Ansible</li>
|
||||
<li>Docker</li>
|
||||
</ul>
|
||||
<h3>Associated Software Developer / DevOps Engineer:</h3>
|
||||
<ul class="pl-5 list-disc">
|
||||
<li>Developed web-based tools for the DevOps team to use</li>
|
||||
<li>
|
||||
Updated Jenkins pipelines that the team uses to manage one of the most important
|
||||
pipelines that the team manages.
|
||||
</li>
|
||||
<li>
|
||||
Created new scripts that were used to clean up multiple terabytes of unused data
|
||||
that led to improvements in the performance of the other scripts running on the same
|
||||
server as well as the performance of the backup system
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-5"></div>
|
||||
<div class="dark:text-white text-black">
|
||||
<h2 class="py-2 text-3xl">Education</h2>
|
||||
<div>
|
||||
<div>
|
||||
<h1>University of Surrey</h1>
|
||||
<div class="ml-5">
|
||||
<h2>July 2020 - June 2024</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--div class="p-5"></div>
|
||||
<div>TODO: Previous projetcs</div -->
|
||||
<!-- div class="p-5"></div>
|
||||
<div>TODO: Info form</div -->
|
||||
</div>
|
||||
</div>
|
116
site/src/routes/flair/+page.svelte
Normal file
116
site/src/routes/flair/+page.svelte
Normal file
@ -0,0 +1,116 @@
|
||||
<script lang="ts">
|
||||
import { flairStore, type Flair as FlairModel } from '$lib/FlairStore.svelte';
|
||||
import { deleteR, preventDefault, put } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
import NavBar from '../NavBar.svelte';
|
||||
import Flair from './Flair.svelte';
|
||||
|
||||
let flair: FlairModel = $state({} as unknown as FlairModel);
|
||||
|
||||
async function create() {
|
||||
try {
|
||||
await put('flair/', flair);
|
||||
flair = {} as unknown as FlairModel;
|
||||
flairStore.loadItems(true);
|
||||
} catch (e) {
|
||||
// TODO: Show to user
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function remove(id: string) {
|
||||
try {
|
||||
await deleteR(`flair/${id}`);
|
||||
flairStore.loadItems(true);
|
||||
} catch (e) {
|
||||
// TODO: Show to user
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
let edit: FlairModel | undefined = $state();
|
||||
|
||||
onMount(() => {
|
||||
flairStore.loadItems();
|
||||
});
|
||||
|
||||
async function update() {
|
||||
try {
|
||||
await put('flair/update', edit);
|
||||
edit = undefined;
|
||||
flairStore.loadItems(true);
|
||||
} catch (e) {
|
||||
// TODO: Show to user
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<NavBar />
|
||||
|
||||
<div class="p-2 flex flex-col gap-2">
|
||||
<!-- Create -->
|
||||
<div class="card p-2 rounded-lg">
|
||||
<form class="flex flex-wrap gap-2" onsubmit={preventDefault(create)}>
|
||||
<fieldset>
|
||||
<label class="flabel" for="color">Color</label>
|
||||
<input required type="color" id="color" class="finput" bind:value={flair.color} />
|
||||
</fieldset>
|
||||
<fieldset class="flex-grow">
|
||||
<label class="flabel" for="name">Name</label>
|
||||
<input required id="name" class="w-full finput" bind:value={flair.name} />
|
||||
</fieldset>
|
||||
<fieldset class="flex-grow">
|
||||
<label class="flabel" for="expr">Expr</label>
|
||||
<input required id="expr" class="w-full finput" bind:value={flair.expr} />
|
||||
</fieldset>
|
||||
<div class="btns w-full">
|
||||
<button class="btn-confirm">Create</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- List -->
|
||||
<div class="card rounded-lg p-2">
|
||||
<h1>Flairs</h1>
|
||||
{#each flairStore.flairs.filter((a) => !flair.name || ` ${flair.name} `.match(new RegExp(a.expr, 'i'))) as item}
|
||||
<div class="p-1 flex items-center gap-2">
|
||||
<button
|
||||
onclick={() => {
|
||||
edit = item;
|
||||
}}
|
||||
>
|
||||
<Flair {item} />
|
||||
</button>
|
||||
<div class="inline text-white">
|
||||
Expr: {item.expr}
|
||||
</div>
|
||||
<div class="flex-grow"></div>
|
||||
<button class="btn-danger" onclick={preventDefault(() => remove(item.id))}> Remove </button>
|
||||
</div>
|
||||
{#if item.id == edit?.id}
|
||||
<form onsubmit={preventDefault(update)} class="shadow-inner p-2 rounded-xl">
|
||||
<fieldset>
|
||||
<label class="flabel" for="color">Color</label>
|
||||
<input required type="color" id="color" bind:value={edit.color} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label class="flabel" for="name">Name</label>
|
||||
<input required id="name" class="finput w-full" bind:value={edit.name} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label class="flabel" for="expr">Expr</label>
|
||||
<input required id="expr" class="finput w-full" bind:value={edit.expr} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label class="flabel" for="description">Description</label>
|
||||
<textarea required id="description" class="finput w-full" bind:value={edit.description}
|
||||
></textarea>
|
||||
</fieldset>
|
||||
<div class="btns w-full">
|
||||
<button class="btn-confirm">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
42
site/src/routes/flair/Flair.svelte
Normal file
42
site/src/routes/flair/Flair.svelte
Normal file
@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import type { Application } from '$lib/ApplicationsStore.svelte';
|
||||
import type { Flair } from '$lib/FlairStore.svelte';
|
||||
import { deleteR, preventDefault } from '$lib/utils';
|
||||
let {
|
||||
item,
|
||||
allowDelete,
|
||||
updateApplication,
|
||||
application
|
||||
}: {
|
||||
application?: Application;
|
||||
item: Flair;
|
||||
allowDelete?: boolean;
|
||||
updateApplication?: (item: Application) => void;
|
||||
} = $props();
|
||||
|
||||
async function remove() {
|
||||
if (!allowDelete || !application || !updateApplication) return;
|
||||
try {
|
||||
updateApplication(await deleteR(`application/flair/${application.id}/${item.id}`));
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
let onTop = $state(false);
|
||||
</script>
|
||||
|
||||
<button
|
||||
style="background: {item.color}"
|
||||
class="inline px-2 py-1 rounded-lg relative"
|
||||
onclick={preventDefault(remove)}
|
||||
onmouseenter={() => (onTop = true)}
|
||||
onmouseleave={() => (onTop = false)}
|
||||
>
|
||||
{item.name}
|
||||
{#if onTop && allowDelete}
|
||||
<span style="background: {item.color}" class="bi bi-trash-fill text-danger absolute right-0"
|
||||
></span>
|
||||
{/if}
|
||||
</button>
|
57
site/src/routes/login/+page.svelte
Normal file
57
site/src/routes/login/+page.svelte
Normal file
@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { userStore } from '$lib/UserStore.svelte';
|
||||
import { post, preventDefault } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
onMount(() => {
|
||||
if (userStore.isLoggedIn) {
|
||||
goto('/');
|
||||
}
|
||||
});
|
||||
|
||||
let userData = $state({
|
||||
email: '',
|
||||
password: ''
|
||||
});
|
||||
|
||||
async function register() {
|
||||
console.log('this is a requeset');
|
||||
try {
|
||||
const r = await post('user/login', userData);
|
||||
userStore.user = r;
|
||||
goto('/');
|
||||
} catch (e) {
|
||||
// TODO messages
|
||||
console.log(e);
|
||||
return;
|
||||
}
|
||||
|
||||
userData = {
|
||||
email: '',
|
||||
password: ''
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full h-lvh flex justify-center items-center">
|
||||
<form class="card p-3 min-w-[300px]" onsubmit={preventDefault(register)}>
|
||||
<h1 class="text-center">Login</h1>
|
||||
<fieldset class="py-2">
|
||||
<label class="flabel" for="email">Email</label>
|
||||
<input required class="finput" id="email" type="email" bind:value={userData.email} />
|
||||
</fieldset>
|
||||
<fieldset class="py-2">
|
||||
<label class="flabel" for="password">Password</label>
|
||||
<input required class="finput" id="password" type="password" bind:value={userData.password} />
|
||||
</fieldset>
|
||||
<div class="btns">
|
||||
<button type="submit" class="btn-confirm"> Login </button>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button class="text-secudanry" type="button" onclick={() => goto('/register')}>
|
||||
Register
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
61
site/src/routes/register/+page.svelte
Normal file
61
site/src/routes/register/+page.svelte
Normal file
@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { userStore } from '$lib/UserStore.svelte';
|
||||
import { post, preventDefault } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
onMount(() => {
|
||||
if (userStore.isLoggedIn) {
|
||||
goto('/');
|
||||
}
|
||||
});
|
||||
|
||||
let userData = $state({
|
||||
username: '',
|
||||
email: '',
|
||||
password: ''
|
||||
});
|
||||
|
||||
async function register() {
|
||||
console.log('this is a requeset');
|
||||
try {
|
||||
const r = await post('user/register', userData);
|
||||
userStore.user = r;
|
||||
goto('/');
|
||||
} catch (e) {
|
||||
// TODO messages
|
||||
console.log(e);
|
||||
return;
|
||||
}
|
||||
|
||||
userData = {
|
||||
username: '',
|
||||
email: '',
|
||||
password: ''
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full h-lvh flex justify-center items-center">
|
||||
<form class="bg-third rounded-lg p-3 min-w-[300px]" onsubmit={preventDefault(register)}>
|
||||
<h1 class="text-center">Register</h1>
|
||||
<fieldset class="py-2">
|
||||
<label class="flabel" for="user">User</label>
|
||||
<input required class="finput" id="user" bind:value={userData.username} />
|
||||
</fieldset>
|
||||
<fieldset class="py-2">
|
||||
<label class="flabel" for="email">Email</label>
|
||||
<input required class="finput" id="email" type="email" bind:value={userData.email} />
|
||||
</fieldset>
|
||||
<fieldset class="py-2">
|
||||
<label class="flabel" for="password">Password</label>
|
||||
<input required class="finput" id="password" type="password" bind:value={userData.password} />
|
||||
</fieldset>
|
||||
<div class="btns">
|
||||
<button type="submit" class="btn-confirm"> Register </button>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button class="text-secudanry" type="button" onclick={() => goto('/login')}> Login </button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
34
site/src/routes/submit/+page.svelte
Normal file
34
site/src/routes/submit/+page.svelte
Normal file
@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { applicationStore } from '$lib/ApplicationsStore.svelte';
|
||||
import { post, preventDefault } from '$lib/utils';
|
||||
import NavBar from '../NavBar.svelte';
|
||||
|
||||
const text = $state({
|
||||
text: ''
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
try {
|
||||
await post('application/text', text);
|
||||
applicationStore.loadApplications(true);
|
||||
goto('/');
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<NavBar />
|
||||
|
||||
<div class="flex justify-center h-4/6">
|
||||
<form onsubmit={preventDefault(submit)} class="card p-5 rounded-lg w-2/5">
|
||||
<fieldset>
|
||||
<label for="text" class="flabel">Text</label>
|
||||
<textarea id="text" class="finput h-96" bind:value={text.text}></textarea>
|
||||
</fieldset>
|
||||
<div class="btns">
|
||||
<button class="btn-confirm"> Submit </button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
40
site/src/routes/work-area/ExtractTextDialog.svelte
Normal file
40
site/src/routes/work-area/ExtractTextDialog.svelte
Normal file
@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { post, preventDefault } from '$lib/utils';
|
||||
|
||||
let {
|
||||
dialog = $bindable(),
|
||||
onreload,
|
||||
id
|
||||
}: { dialog: HTMLDialogElement; onreload: () => void; id: string } = $props();
|
||||
|
||||
let data = $state({
|
||||
text: ''
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
try {
|
||||
await post('application/text/flair', {
|
||||
id,
|
||||
...data
|
||||
});
|
||||
data.text = '';
|
||||
dialog.close();
|
||||
onreload();
|
||||
} catch (e) {
|
||||
// Show message to the user
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog class="card" bind:this={dialog}>
|
||||
<form onsubmit={preventDefault(submit)}>
|
||||
<fieldset>
|
||||
<label class="flabel" for="text">Text</label>
|
||||
<textarea class="finput min-w-96 min-h-96" id="text" bind:value={data.text}></textarea>
|
||||
</fieldset>
|
||||
<div class="btns">
|
||||
<button type="submit" class="btn-confirm">Extract</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
96
site/src/routes/work-area/NewUrlDialog.svelte
Normal file
96
site/src/routes/work-area/NewUrlDialog.svelte
Normal file
@ -0,0 +1,96 @@
|
||||
<script lang="ts">
|
||||
import type { Application } from '$lib/ApplicationsStore.svelte';
|
||||
import { post, preventDefault } from '$lib/utils';
|
||||
|
||||
let {
|
||||
dialog = $bindable(),
|
||||
openWindow = $bindable(),
|
||||
onreload,
|
||||
id
|
||||
}: {
|
||||
dialog: HTMLDialogElement;
|
||||
onreload: (item: Application) => void;
|
||||
id: string;
|
||||
openWindow?: Window | null;
|
||||
} = $props();
|
||||
|
||||
const data = $state({
|
||||
url: ''
|
||||
});
|
||||
|
||||
let form: HTMLFormElement | undefined = $state();
|
||||
|
||||
async function submit() {
|
||||
try {
|
||||
const newItem = await post('application/update/url', {
|
||||
id,
|
||||
...data
|
||||
});
|
||||
data.url = '';
|
||||
dialog.close();
|
||||
onreload(newItem);
|
||||
} catch (e) {
|
||||
// Show message to the user
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
let hasExtension = $state(false);
|
||||
|
||||
$effect(() => {
|
||||
function onMessage(e: MessageEvent) {
|
||||
if (e.data.type === 'MY_GET_URL_R') {
|
||||
if (e.data.error) {
|
||||
console.log(e.data);
|
||||
if (e.data.data.length === 0) {
|
||||
console.log('TODO inform user to mark page');
|
||||
} else {
|
||||
console.log('TODO inform use to unmark page');
|
||||
}
|
||||
return;
|
||||
}
|
||||
data.url = e.data.url ?? '';
|
||||
window.requestAnimationFrame(() => {
|
||||
if (!form?.reportValidity()) {
|
||||
return;
|
||||
}
|
||||
submit();
|
||||
});
|
||||
} else if (e.data.type === 'HAS_EXTENSION') {
|
||||
hasExtension = true;
|
||||
console.log('got ext');
|
||||
}
|
||||
|
||||
if (!hasExtension) {
|
||||
window.postMessage({ type: 'HAS_EXTENSION_Q' });
|
||||
}
|
||||
}
|
||||
|
||||
console.log('setting up');
|
||||
|
||||
window.addEventListener('message', onMessage);
|
||||
return () => {
|
||||
window.removeEventListener('message', onMessage);
|
||||
};
|
||||
});
|
||||
|
||||
function askForUrl() {
|
||||
console.log('sending');
|
||||
window.postMessage({ type: 'MY_GET_URL' });
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog class="card" bind:this={dialog}>
|
||||
<form bind:this={form} onsubmit={preventDefault(submit)}>
|
||||
<fieldset>
|
||||
<label class="flabel" for="text">Url</label>
|
||||
<textarea class="finput min-w-96 min-h-96" id="text" bind:value={data.url}></textarea>
|
||||
</fieldset>
|
||||
<div class="btns">
|
||||
<button type="submit" class="btn-confirm">Update</button>
|
||||
{#if hasExtension}
|
||||
<button type="button" class="btn-confirm" onclick={askForUrl}>Get Url</button>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
377
site/src/routes/work-area/WorkArea.svelte
Normal file
377
site/src/routes/work-area/WorkArea.svelte
Normal file
@ -0,0 +1,377 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
ApplicationStatus,
|
||||
ApplicationStatusMaping,
|
||||
applicationStore,
|
||||
type Application
|
||||
} from '$lib/ApplicationsStore.svelte';
|
||||
|
||||
import { put, preventDefault, post, get, deleteR } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
import ExtractTextDialog from './ExtractTextDialog.svelte';
|
||||
import Flair from '../flair/Flair.svelte';
|
||||
import NewUrlDialog from './NewUrlDialog.svelte';
|
||||
import { userStore } from '$lib/UserStore.svelte';
|
||||
|
||||
let activeItem: Application | undefined = $state();
|
||||
|
||||
let extractTokens: HTMLDialogElement;
|
||||
let changeUrl: HTMLDialogElement;
|
||||
|
||||
let preparingToDrop = $state(false);
|
||||
|
||||
async function activate(item?: Application) {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (activeItem && activeItem.id !== item.id && activeItem.status === 1) {
|
||||
// Deactivate active item
|
||||
try {
|
||||
await put('application/status', {
|
||||
id: activeItem.id,
|
||||
status: 0
|
||||
});
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.status === 0) {
|
||||
openWindow(item.url);
|
||||
}
|
||||
|
||||
try {
|
||||
await put('application/status', {
|
||||
id: item.id,
|
||||
status: ApplicationStatus.WorkingOnIt
|
||||
});
|
||||
activeItem = await get('application/active');
|
||||
if (!activeItem?.unique_url) {
|
||||
window.requestAnimationFrame(() => {
|
||||
changeUrl.showModal();
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
}
|
||||
applicationStore.loadApplications(true);
|
||||
}
|
||||
|
||||
function openWindow(url: string) {
|
||||
if (!url.startsWith('https://')) {
|
||||
url = `https://${url}`;
|
||||
}
|
||||
|
||||
window.open(
|
||||
url,
|
||||
'new window',
|
||||
`location,height=${window.screen.height},width=${window.screen.width},scrollbars,status,toolbar,menubar,popup`
|
||||
);
|
||||
}
|
||||
|
||||
async function loadActive() {
|
||||
try {
|
||||
activeItem = await get('application/active');
|
||||
if (activeItem?.unique_url === null) {
|
||||
changeUrl.showModal();
|
||||
}
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
userStore.checkLogin();
|
||||
loadActive();
|
||||
});
|
||||
|
||||
async function moveStatus(status: number) {
|
||||
if (!activeItem) return;
|
||||
// Deactivate active item
|
||||
try {
|
||||
await put('application/status', {
|
||||
id: activeItem.id,
|
||||
status: status
|
||||
});
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
return;
|
||||
}
|
||||
applicationStore.loadApplications(true);
|
||||
activeItem = undefined;
|
||||
//openedWindow?.close();
|
||||
//openedWindow = undefined;
|
||||
}
|
||||
|
||||
async function remove() {
|
||||
if (!activeItem) return;
|
||||
// Deactivate active item
|
||||
try {
|
||||
await deleteR(`application/${activeItem.id}`);
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
return;
|
||||
}
|
||||
applicationStore.loadApplications(true);
|
||||
activeItem = undefined;
|
||||
//openedWindow?.close();
|
||||
//openedWindow = undefined;
|
||||
}
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
await put('application/update', activeItem);
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
}
|
||||
}
|
||||
|
||||
async function resetUrl() {
|
||||
try {
|
||||
activeItem = await post(`application/reset/url/${activeItem?.id}`, {});
|
||||
} catch (e) {
|
||||
// Show User
|
||||
console.log('info data', e);
|
||||
}
|
||||
}
|
||||
|
||||
let drag = $state(true);
|
||||
|
||||
const statusMapping: string = $derived(
|
||||
(ApplicationStatusMaping[
|
||||
activeItem?.status as (typeof ApplicationStatus)[keyof typeof ApplicationStatus]
|
||||
] as string) ?? ''
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full gap-2 min-w-0" role="none">
|
||||
{#if activeItem && (!applicationStore.dragging || applicationStore.dragging?.id === activeItem.id)}
|
||||
<div
|
||||
draggable={drag}
|
||||
ondrag={() => {
|
||||
applicationStore.dragStart(activeItem);
|
||||
}}
|
||||
ondragend={() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
applicationStore.dragEnd();
|
||||
});
|
||||
}}
|
||||
role="none"
|
||||
class="flex flex-col p-2 h-full gap-2 card min-w-0 flex-grow"
|
||||
>
|
||||
<div class="w-full">
|
||||
{#if activeItem.status != 1}
|
||||
<div class="bg-danger text-white p-2 rounded-lg text-lg font-bold">
|
||||
{statusMapping}
|
||||
</div>
|
||||
{/if}
|
||||
<fieldset>
|
||||
<label class="flabel" for="title">Title</label>
|
||||
<input class="finput" id="title" bind:value={activeItem.title} onchange={save} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label class="flabel" for="payrange">Pay Range</label>
|
||||
<input class="finput" id="payrange" bind:value={activeItem.payrange} onchange={save} />
|
||||
</fieldset>
|
||||
<fieldset
|
||||
draggable="false"
|
||||
onmouseenter={() => (drag = false)}
|
||||
onmouseleave={() => (drag = true)}
|
||||
class="max-w-full min-w-0 overflow-hidden"
|
||||
>
|
||||
<div class="flabel">Url</div>
|
||||
<div class="finput bg-white w-full break-keep">
|
||||
{activeItem.url}
|
||||
</div>
|
||||
</fieldset>
|
||||
{#if activeItem.unique_url}
|
||||
<fieldset
|
||||
draggable="false"
|
||||
onmouseenter={() => (drag = false)}
|
||||
onmouseleave={() => (drag = true)}
|
||||
>
|
||||
<div class="flabel">Unique Url</div>
|
||||
<div class="finput bg-white">
|
||||
{activeItem.unique_url}
|
||||
</div>
|
||||
</fieldset>
|
||||
{/if}
|
||||
<div>
|
||||
<div class="flabel">Tags</div>
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
{#each activeItem.flairs as item}
|
||||
<Flair
|
||||
{item}
|
||||
allowDelete
|
||||
application={activeItem}
|
||||
updateApplication={(item) => (activeItem = item)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<fieldset>
|
||||
<label class="flabel" for="extra">Extra Info</label>
|
||||
<textarea class="finput" id="extra" bind:value={activeItem.extra_data} onchange={save}
|
||||
></textarea>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="flex btns">
|
||||
<button
|
||||
class="btn-confirm"
|
||||
onclick={() => {
|
||||
openWindow(activeItem!.url);
|
||||
}}
|
||||
>
|
||||
Open
|
||||
</button>
|
||||
<button
|
||||
class="btn-primary"
|
||||
onclick={() => window.open(`/cv?id=${activeItem!.id}`, '_blank')}
|
||||
>
|
||||
Open CV
|
||||
</button>
|
||||
<button class="btn-primary" onclick={() => extractTokens.showModal()}>
|
||||
Extract Flair
|
||||
</button>
|
||||
{#if activeItem.original_url == null}
|
||||
<button class="btn-primary" onclick={() => changeUrl.showModal()}> Update Url </button>
|
||||
{/if}
|
||||
{#if activeItem.original_url != null}
|
||||
<button class="btn-danger" onclick={resetUrl}> Reset Url </button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if applicationStore.dragging}
|
||||
<div class="flex w-full flex-grow rounded-lg p-1 gap-2">
|
||||
<!-- Ignore -->
|
||||
<div
|
||||
class="grid place-items-center w-full card p-2 rounded-lg"
|
||||
role="none"
|
||||
ondragover={preventDefault(() => {})}
|
||||
ondragenter={preventDefault(() => {})}
|
||||
ondrop={() => {
|
||||
moveStatus(ApplicationStatus.Ignore);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
class="bi bi-trash-fill text-7xl absolute"
|
||||
class:animate-bounce={applicationStore.dragging}
|
||||
></span>
|
||||
<span class="bi bi-trash-fill text-7xl opacity-0"></span>
|
||||
<div class="text-xl">Drop Application Ignore it.</div>
|
||||
</div>
|
||||
|
||||
<!-- Expired -->
|
||||
<div
|
||||
class="grid place-items-center w-full card p-2 rounded-lg"
|
||||
role="none"
|
||||
ondragover={preventDefault(() => {})}
|
||||
ondragenter={preventDefault(() => {})}
|
||||
ondrop={() => {
|
||||
moveStatus(ApplicationStatus.Expired);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
class="bi bi-clock-fill text-7xl text-orange-500 absolute"
|
||||
class:animate-bounce={applicationStore.dragging}
|
||||
></span>
|
||||
<span class="bi bi-clock-fill text-7xl text-orange-500 opacity-0"></span>
|
||||
<div class="text-orange-500 text-xl">Mark as expired.</div>
|
||||
</div>
|
||||
|
||||
<!-- Repeated -->
|
||||
<div
|
||||
class="grid place-items-center w-full card p-2 rounded-lg"
|
||||
role="none"
|
||||
ondragover={preventDefault(() => {})}
|
||||
ondragenter={preventDefault(() => {})}
|
||||
ondrop={() => {
|
||||
remove();
|
||||
}}
|
||||
>
|
||||
<span
|
||||
class="bi bi-trash-fill text-7xl text-danger absolute"
|
||||
class:animate-bounce={applicationStore.dragging}
|
||||
></span>
|
||||
<span class="bi bi-trash-fill text-7xl text-danger opacity-0"></span>
|
||||
<div class="text-danger text-xl">This is repeated</div>
|
||||
</div>
|
||||
|
||||
<!-- Applyed -->
|
||||
<div
|
||||
class="grid place-items-center w-full card p-2 rounded-lg"
|
||||
role="none"
|
||||
ondragover={preventDefault(() => {})}
|
||||
ondragenter={preventDefault(() => {})}
|
||||
ondrop={async () => {
|
||||
await moveStatus(ApplicationStatus.Applyed);
|
||||
applicationStore.loadAplyed(true);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
class="bi bi-server text-7xl text-confirm absolute"
|
||||
class:animate-bounce={applicationStore.dragging}
|
||||
></span>
|
||||
<span class="bi bi-server text-7xl text-confirm opacity-0"></span>
|
||||
<div class="text-confirm text-xl">Apply</div>
|
||||
</div>
|
||||
|
||||
<!-- Rejected -->
|
||||
<div
|
||||
class="grid place-items-center w-full card p-2 rounded-lg"
|
||||
role="none"
|
||||
ondragover={preventDefault(() => {})}
|
||||
ondragenter={preventDefault(() => {})}
|
||||
ondrop={() => {
|
||||
moveStatus(ApplicationStatus.ApplyedButSaidNo);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
class="bi bi-fire text-danger text-7xl absolute"
|
||||
class:animate-bounce={applicationStore.dragging}
|
||||
></span>
|
||||
<span class="bi bi-fire text-7xl text-danger opacity-0"></span>
|
||||
<div class="text-danger text-xl">I was rejeted :(.</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
class="p-2 h-full w-full gap-2 flex-grow card grid place-items-center"
|
||||
ondragover={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
ondragenter={preventDefault(() => {})}
|
||||
ondrop={() => {
|
||||
activate(applicationStore.dragging);
|
||||
}}
|
||||
role="none"
|
||||
>
|
||||
<div class="text-center relative">
|
||||
<span
|
||||
class="bi bi-layers-fill text-7xl text-white absolute"
|
||||
class:animate-bounce={applicationStore.dragging}
|
||||
></span>
|
||||
<span class="bi bi-layers-fill text-7xl text-white opacity-0"></span>
|
||||
<div class="text-white text-xl">Drop Application To Apply To.</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<ExtractTextDialog id={activeItem?.id ?? ''} bind:dialog={extractTokens} onreload={loadActive} />
|
||||
|
||||
{#if !activeItem?.original_url}
|
||||
<NewUrlDialog
|
||||
id={activeItem?.id ?? ''}
|
||||
bind:dialog={changeUrl}
|
||||
onreload={(item) => (activeItem = item)}
|
||||
/>
|
||||
{/if}
|
BIN
site/static/favicon.png
Normal file
BIN
site/static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
site/static/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf
Normal file
BIN
site/static/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/JetBrainsMono-VariableFont_wght.ttf
Normal file
BIN
site/static/fonts/JetBrainsMono-VariableFont_wght.ttf
Normal file
Binary file not shown.
93
site/static/fonts/OFL.txt
Normal file
93
site/static/fonts/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
79
site/static/fonts/README.txt
Normal file
79
site/static/fonts/README.txt
Normal file
@ -0,0 +1,79 @@
|
||||
JetBrains Mono Variable Font
|
||||
============================
|
||||
|
||||
This download contains JetBrains Mono as both variable fonts and static fonts.
|
||||
|
||||
JetBrains Mono is a variable font with this axis:
|
||||
wght
|
||||
|
||||
This means all the styles are contained in these files:
|
||||
JetBrainsMono-VariableFont_wght.ttf
|
||||
JetBrainsMono-Italic-VariableFont_wght.ttf
|
||||
|
||||
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||
in those cases you can use the static font files for JetBrains Mono:
|
||||
static/JetBrainsMono-Thin.ttf
|
||||
static/JetBrainsMono-ExtraLight.ttf
|
||||
static/JetBrainsMono-Light.ttf
|
||||
static/JetBrainsMono-Regular.ttf
|
||||
static/JetBrainsMono-Medium.ttf
|
||||
static/JetBrainsMono-SemiBold.ttf
|
||||
static/JetBrainsMono-Bold.ttf
|
||||
static/JetBrainsMono-ExtraBold.ttf
|
||||
static/JetBrainsMono-ThinItalic.ttf
|
||||
static/JetBrainsMono-ExtraLightItalic.ttf
|
||||
static/JetBrainsMono-LightItalic.ttf
|
||||
static/JetBrainsMono-Italic.ttf
|
||||
static/JetBrainsMono-MediumItalic.ttf
|
||||
static/JetBrainsMono-SemiBoldItalic.ttf
|
||||
static/JetBrainsMono-BoldItalic.ttf
|
||||
static/JetBrainsMono-ExtraBoldItalic.ttf
|
||||
|
||||
Get started
|
||||
-----------
|
||||
|
||||
1. Install the font files you want to use
|
||||
|
||||
2. Use your app's font picker to view the font family and all the
|
||||
available styles
|
||||
|
||||
Learn more about variable fonts
|
||||
-------------------------------
|
||||
|
||||
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||
https://variablefonts.typenetwork.com
|
||||
https://medium.com/variable-fonts
|
||||
|
||||
In desktop apps
|
||||
|
||||
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||
|
||||
Online
|
||||
|
||||
https://developers.google.com/fonts/docs/getting_started
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||
|
||||
Installing fonts
|
||||
|
||||
MacOS: https://support.apple.com/en-us/HT201749
|
||||
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||
|
||||
Android Apps
|
||||
|
||||
https://developers.google.com/fonts/docs/android
|
||||
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||
|
||||
License
|
||||
-------
|
||||
Please read the full license text (OFL.txt) to understand the permissions,
|
||||
restrictions and requirements for usage, redistribution, and modification.
|
||||
|
||||
You can use them in your products & projects – print or digital,
|
||||
commercial or otherwise.
|
||||
|
||||
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||
license for all details.
|
BIN
site/static/fonts/static/JetBrainsMono-Bold.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-Bold.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-BoldItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-ExtraBold.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-ExtraBold.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-ExtraBoldItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-ExtraBoldItalic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-ExtraLight.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-ExtraLightItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-ExtraLightItalic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-Italic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-Italic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-Light.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-Light.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-LightItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-LightItalic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-Medium.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-Medium.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-MediumItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-Regular.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-Regular.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-SemiBold.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-SemiBold.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-SemiBoldItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-SemiBoldItalic.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-Thin.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-Thin.ttf
Normal file
Binary file not shown.
BIN
site/static/fonts/static/JetBrainsMono-ThinItalic.ttf
Normal file
BIN
site/static/fonts/static/JetBrainsMono-ThinItalic.ttf
Normal file
Binary file not shown.
18
site/svelte.config.js
Normal file
18
site/svelte.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
16
site/tailwind.config.js
Normal file
16
site/tailwind.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#FFCCC9',
|
||||
secudanry: '#011627',
|
||||
third: '#757780',
|
||||
danger: '#F71735',
|
||||
confirm: '#41EAD4'
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: []
|
||||
};
|
19
site/tsconfig.json
Normal file
19
site/tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
6
site/vite.config.ts
Normal file
6
site/vite.config.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
Loading…
Reference in New Issue
Block a user