Skip to content

Commit

Permalink
Merge pull request #93 from LikeKNU/Hotfix/CafeteriaSequence
Browse files Browse the repository at this point in the history
์‹๋‹น ์ˆœ์„œ ๋ณ€๊ฒฝ
  • Loading branch information
jcw1031 authored Jan 13, 2024
2 parents 84203e2 + 0ed6c29 commit 485d525
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 39 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ jar {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
compileOnly 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/ac/knu/likeknu/config/SecurityConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ac.knu.likeknu.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

@Value("${admin.username}")
private String username;
@Value("${admin.password}")
private String password;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(registry -> registry.requestMatchers("/api/**").permitAll()
.anyRequest().authenticated())
.formLogin(security -> security.loginPage("/admin/login")
.defaultSuccessUrl("/admin/messages")
.permitAll()).csrf(AbstractHttpConfigurer::disable)
.build();
}

@Bean
public UserDetailsService userDetailsService() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
UserDetails admin = User.withUsername(username)
.password(password)
.passwordEncoder(encoder::encode)
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(admin);
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
21 changes: 21 additions & 0 deletions src/main/java/ac/knu/likeknu/controller/AdminController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ac.knu.likeknu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/admin")
@Controller
public class AdminController {

@GetMapping("/login")
public String loginForm() {
return "login";
}

@GetMapping("/messages")
public String registerMessageForm(Model model) {
return "registerMessage";
}
}
12 changes: 6 additions & 6 deletions src/main/java/ac/knu/likeknu/domain/value/CafeteriaName.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
@Getter
public enum CafeteriaName {

STUDENT_CAFETERIA("ํ•™์ƒ์‹๋‹น", 1),
DORMITORY("์ƒํ™œ๊ด€์‹๋‹น", 2),
STUDENT_CAFETERIA("ํ•™์ƒ์‹๋‹น", 10),
DORMITORY("์ƒํ™œ๊ด€์‹๋‹น", 20),
EMPLOYEE_CAFETERIA("์ง์›์‹๋‹น", 3),
SODAM("์†Œ๋‹ด", 4),
NEULSOM("๋Š˜์†œ", 5),
EUNHAENGSA_VISION("์€ํ–‰์‚ฌ/๋น„์ „", 6),
DREAM("๋“œ๋ฆผ", 7);
SODAM("์†Œ๋‹ด", 40),
NEULSOM("๋Š˜์†œ", 50),
EUNHAENGSA_VISION("์€ํ–‰์‚ฌ/๋น„์ „", 1),
DREAM("๋“œ๋ฆผ", 2);

private final String cafeteriaName;
private final int sequence;
Expand Down
6 changes: 1 addition & 5 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA}?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

spring.jpa.hibernate.ddl-auto=validate
spring.profiles.active=dev
132 changes: 132 additions & 0 deletions src/main/resources/templates/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>๋กœ๊ทธ์ธ</title>
<link href="https://getbootstrap.com/docs/5.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
html,
body {
height: 100%;
}

.form-signin {
max-width: 330px;
padding: 1rem;
}

.form-signin .form-floating:focus-within {
z-index: 2;
}

.form-signin input[type="text"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}

.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>
</head>
<body class="d-flex align-items-center py-4 bg-body-tertiary">
<main class="form-signin w-100 m-auto">
<form action="/admin/login" method="POST">
<img class="mb-4"
src="https://avatars.githubusercontent.com/u/144087727?s=400&u=0234d20a40888b3d67e1576444a2511e7f351c91&v=4"
alt="" width="72" height="72">
<h1 class="h3 mb-3 fw-normal">๊ณต์ฃผ๋Œ€์ฒ˜๋Ÿผ ๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ</h1>
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="Username" name="username">
<label for="floatingInput">๊ด€๋ฆฌ์ž ์•„์ด๋””</label>
</div>
<div class="form-floating mb-5">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password" name="password">
<label for="floatingPassword">๊ด€๋ฆฌ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ</label>
</div>
<button class="btn btn-primary w-100 py-2" type="submit">๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ</button>
<p class="mt-5 mb-3 text-body-secondary">ยฉ ๊ณต์ฃผ๋Œ€์ฒ˜๋Ÿผ</p>
</form>
</main>
<script>
(() => {
'use strict'

const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)

const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}

return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}

const setTheme = theme => {
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark')
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}

setTheme(getPreferredTheme())

const showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.querySelector('#bd-theme')

if (!themeSwitcher) {
return
}

const themeSwitcherText = document.querySelector('#bd-theme-text')
const activeThemeIcon = document.querySelector('.theme-icon-active use')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')

document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
element.setAttribute('aria-pressed', 'false')
})

btnToActive.classList.add('active')
btnToActive.setAttribute('aria-pressed', 'true')
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)

if (focus) {
themeSwitcher.focus()
}
}

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})

window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme())

document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
setStoredTheme(theme)
setTheme(theme)
showActiveTheme(theme, true)
})
})
})
})()
</script>
</body>
</html>
87 changes: 87 additions & 0 deletions src/main/resources/templates/registerMessage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>๊ณต์ฃผ๋Œ€์ฒ˜๋Ÿผ ๊ด€๋ฆฌ์ž</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<div class="container p-5">
<form class="row g-3 needs-validation" method="POST" action="/admin/messages">
<div class="col-md-4">
<label for="notificationSummary" class="form-label"><strong>์•Œ๋ฆผ ์š”์•ฝ</strong></label>
<input type="text" class="form-control" id="notificationSummary" placeholder="์ง€ํ•˜์ฒ  4ํ˜ธ์„  ์ง€์—ฐ"
name="notificationSummary" required>
</div>
<div class="col-md-4">
<label for="notificationContents" class="form-label"><strong>์•Œ๋ฆผ ๋‚ด์šฉ</strong></label>
<input type="text" class="form-control" id="notificationContents" placeholder="ํ˜„์žฌ ์ง€ํ•˜์ฒ  4ํ˜ธ์„ ์ด ์ง€์—ฐ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค."
name="notificationContents" required>
</div>
<div class="form-outline datetimepicker" data-mdb-inline="true">
<label for="notificationDateTime" class="form-label"><strong>์•Œ๋ฆผ ์‹œ๊ฐ„</strong></label>
<input type="datetime-local" class="form-control" id="notificationDateTime" name="notificationDate">
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">์•Œ๋ฆผ ๋“ฑ๋ก</button>
</div>
</form>
</div>
<br><br>
<div>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>์•Œ๋ฆผ ์š”์•ฝ</th>
<th>์•Œ๋ฆผ ๋‚ด์šฉ</th>
<th>์•Œ๋ฆผ ์‹œ๊ฐ„</th>
<th></th>
</tr>
</thead>
<tbody>
<tr th:each="notification : ${notifications}">
<td th:text="${notification.id}" id="notificationId"></td>
<td th:text="${notification.summary}"></td>
<td th:text="${notification.content}"></td>
<td th:text="${notification.dateTime}"></td>
<td>
<a id="removeButton" href="#" class="btn btn-danger" role="button">์‚ญ์ œ</a>
</td>
</tr>
</tbody>
</table>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
integrity="sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+"
crossorigin="anonymous"></script>
<script>
const removeButton = document.getElementById('removeButton');
const notificationId = document.getElementById('notificationId').textContent;

if (removeButton) {
removeButton.addEventListener('click', event => {
const confirmation = confirm('์ •๋ง ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?');
if (confirmation) {
fetch(`/admin/notifications/${notificationId}`, {
method: 'DELETE'
})
.then(() => {
alert('์‚ญ์ œ ์™„๋ฃŒ');
location.replace(`/admin/notifications`);
});
} else {
}
});
}
</script>
</html>
28 changes: 0 additions & 28 deletions src/main/resources/templates/test.json

This file was deleted.

0 comments on commit 485d525

Please sign in to comment.