feat: Better styling on web pages, bad-words check now has less edge cases.

This commit is contained in:
2024-12-31 23:57:47 -05:00
parent 8dba393267
commit 26191a15c1
6 changed files with 160 additions and 91 deletions

View File

@@ -1,6 +1,13 @@
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body { body {
background-color: #1E1E2E; background-color: #1E1E2E;
color: white; color: white;
padding: 20px;
margin: 10px;
} }
p { p {
@@ -42,27 +49,72 @@ label {
li { li {
font-size: 20px; font-size: 20px;
padding: 10px;
margin: 10px;
}
ul {
padding: 10px 20px;
}
.description {
padding-top: 20px;
}
.container {
display: flex;
} }
.pros { .pros {
border 2px solid green; flex 1 300px;
border-radius: 10px; width: 50%;
background-color: MediumSeaGreen; min-height: 200px;
margin: 10px; padding: 5px;
opacity: 0.7;
} }
.cons { .cons {
flex 1 300px;
min-height: 200px;
width: 50%;
padding: 5px;
}
.counter-container {
position: relative;
/* border 5px solid MediumSeaGreen; */
/* border-radius: 5px 5px 0px 0px; */
}
.counter {
position: absolute;
top: 2px;
right: 10px;
}
.counter-label {
position: relative;
top: 2px;
left: 10px;
}
.pros-list {
position: relative;
border 2px solid green;
border-radius: 10px;
background-color: MediumSeaGreen;
}
.cons-list {
position: relative;
border 2px solid green; border 2px solid green;
border-radius: 10px; border-radius: 10px;
background-color: Tomato; background-color: Tomato;
margin: 10px;
opacity: 0.7;
} }
.listHeader { .listHeader {
margin: auto; /* margin: auto; */
padding: 20px; padding: 10px;
} }
.center { .center {

View File

@@ -2,42 +2,49 @@
#export("body"): #export("body"):
<div class="center"> <div class="center">
<h1>Welcome #capitalized(name)</h1> <h1>Welcome #capitalized(name)</h1>
<div class="description">
<p> <p>
Please add your pro's and cons during the talk to the list below. <small>Please add your pro's and cons during the talk to the list below.</small>
</p> </p>
<p> <p>
<small>You can add as many pros and cons as you would like.</small> <small>You can add as many pros and cons as you would like.</small>
</p> </p>
</div>
<form id="proconForm" action="submitProOrCon"> <form id="proconForm" action="submitProOrCon">
<select id="type", name="type"> <select id="type", name="type">
<option value="pro">Pro</option> <option value="pro">Pro</option>
<option value="con">Con</option> <option value="con">Con</option>
</select> </select>
<br> <br>
<br> <input type="text" id="description" name="description" placeholder="Description" required>
<label for="description">Description:</label>
<br>
<input type="text" id="description" name="description" required>
<br> <br>
<br> <br>
<input class="loginButton" type="submit" value="Submit"> <input class="loginButton" type="submit" value="Submit">
</form> </form>
</div> </div>
<div class="container">
<div class="pros"> <div class="pros">
<p class="listHeader">Pros - <small>Count: #count(pros)</small></p> <div class="counter-container">
<ul> <h3 class="counter-label">Pros</h3>
<h3 class="counter">Count: #count(pros)</h3>
</div>
<ul class="pros-list">
#for(item in pros): #for(item in pros):
<li>#(item.description)</li> <li>#(item.description)</li>
#endfor #endfor
</ul> </ul>
</div> </div>
<div class="cons"> <div class="cons">
<p class="listHeader">Cons - <small>Count: #count(cons)</small></p> <div class="counter-container">
<ul> <h3 class="counter-label">Cons</h3>
<h3 class="counter">Count: #count(cons)</h3>
</div>
<ul class="cons-list">
#for(item in cons): #for(item in cons):
<li>#(item.description)</li> <li>#(item.description)</li>
#endfor #endfor
</ul> </ul>
</div> </div>
</div>
#endexport #endexport
#endextend #endextend

View File

@@ -6,7 +6,6 @@
<script src="js/site.js"></script> <script src="js/site.js"></script>
</head> </head>
<body> <body>
<header><h1>Chiller Pro vs. Cons<h1></header>
#import("body") #import("body")
<footer> <footer>
<span>2025 Symposium</span> <span>2025 Symposium</span>

View File

@@ -5,13 +5,18 @@ import Vapor
struct ApiController: RouteCollection { struct ApiController: RouteCollection {
func boot(routes: any RoutesBuilder) throws { func boot(routes: any RoutesBuilder) throws {
let users = routes.grouped("api", "users") let api = routes.grouped("api")
let users = api.grouped("users")
let proCon = api.grouped("procons")
let utils = api.grouped("utils")
users.get(use: usersIndex(req:)) users.get(use: usersIndex(req:))
users.post(use: createUser(req:)) users.post(use: createUser(req:))
let proCon = routes.grouped("api", "procons")
proCon.get(use: prosAndConsIndex(req:)) proCon.get(use: prosAndConsIndex(req:))
proCon.post(use: createProCon(req:)) proCon.post(use: createProCon(req:))
utils.post("check-words", use: checkWords(req:))
} }
@Sendable @Sendable
@@ -39,6 +44,17 @@ struct ApiController: RouteCollection {
return proCon return proCon
} }
@Sendable
func checkWords(req: Request) async throws -> HTTPStatus {
let input = try req.content.decode(CheckWords.self)
try checkForBadWords(in: input.string)
return .ok
}
}
struct CheckWords: Content {
let string: String
} }
struct ProConDTO: Content { struct ProConDTO: Content {

View File

@@ -1,20 +1,20 @@
import Foundation
import Vapor
func checkForBadWords(in string: String) throws { func checkForBadWords(in string: String) throws {
if badWords.contains(string) { let split = string.split(separator: "\n")
throw BadWordError() for string in split {
} else if string.contains(" ") { for word in badWords where string.contains(word) {
let parts = string.split(separator: " ") throw Abort(.badRequest, reason: "Stop using such naughty language.")
for part in parts {
if badWords.contains(String(part)) {
throw BadWordError()
}
} }
} }
} }
struct BadWordError: Error {}
let badWords: [String] = [ let badWords: [String] = [
"420",
"69",
"puppy", "puppy",
"kitty",
"2g1c", "2g1c",
"a-hole", "a-hole",
"a-holes", "a-holes",

View File

@@ -8,64 +8,59 @@ func routes(_ app: Application) throws {
return output return output
} }
app.get("loggedIn") { req in app.get("loggedIn") { req -> View in
guard let userIdString = req.session.data["userId"], guard let user = try await req.currentUser(withProsAndCons: true) else {
let displayName = req.session.data["displayName"], throw Abort(.badRequest)
let userId = UUID(uuidString: userIdString)
else {
return try await req.view.render("/")
} }
guard let user = try await User.query(on: req.db)
.filter(\.$id == userId)
.with(\.$prosAndCons)
.first()
else {
throw Abort(.unauthorized)
}
// let prosAndCons = try await user.$prosAndCons.get(on: req.db)
return try await req.view.render( return try await req.view.render(
"loggedIn", "loggedIn",
LoggedInContext(name: displayName, prosAndCons: user.prosAndCons) LoggedInContext(name: user.displayName, prosAndCons: user.prosAndCons)
) )
} }
app.get("submitProOrCon") { req in app.get("submitProOrCon") { req in
let params = try req.query.decode(SubmitProOrCon.self) let params = try req.query.decode(SubmitProOrCon.self)
guard let userIdString = req.session.data["userId"], guard let userId = req.userId else {
let userId = UUID(uuidString: userIdString)
else {
throw Abort(.unauthorized) throw Abort(.unauthorized)
} }
try checkForBadWords(in: params.description)
let proOrCon = ProCon(type: params.type, description: params.description, userId: userId) let proOrCon = ProCon(type: params.type, description: params.description, userId: userId)
_ = try await req.db.transaction { try await proOrCon.save(on: req.db)
proOrCon.save(on: $0)
}
.get()
return req.redirect(to: "loggedIn") return req.redirect(to: "loggedIn")
} }
app.get("login") { req in app.get("login") { req in
let params = try req.query.decode(LoginParams.self) let params = try req.query.decode(LoginParams.self)
req.logger.info("params: \(params)") req.logger.info("params: \(params)")
do {
try checkForBadWords(in: params.displayName) try checkForBadWords(in: params.displayName)
} catch { let user = User(displayName: params.displayName)
throw Abort(.unauthorized, reason: "Stop using such naughty language.") try await user.save(on: req.db)
req.session.data["userId"] = user.id?.uuidString
return req.redirect(to: "loggedIn")
}
}
private extension Request {
var userId: UUID? {
guard let userIdString = session.data["userId"],
let userId = UUID(uuidString: userIdString)
else {
return nil
}
return userId
} }
let user = User(displayName: params.displayName) func currentUser(withProsAndCons: Bool) async throws -> User? {
_ = try await req.db.transaction { guard let userId = userId else {
user.save(on: $0) return nil
}.get() }
let userId = user.id?.uuidString ?? "nil" var query = User.query(on: db).filter(\.$id == userId)
req.session.data["userId"] = userId if withProsAndCons {
req.session.data["displayName"] = user.displayName query = query.with(\.$prosAndCons)
}
// return try await req.view.render("loggedIn", ["name": user.displayName]) return try await query.first()
return req.redirect(to: "loggedIn")
} }
} }