update for summer theme

This commit is contained in:
tylen
2026-05-05 21:02:25 +03:00
parent 399ea281c2
commit 14da622e5e
10 changed files with 72 additions and 198 deletions

View File

@@ -16,10 +16,10 @@ STARTUP_TABLE_CREATION_QUERIES = {
Name varchar(255) Name varchar(255)
);""", );""",
"hosting": """CREATE TABLE IF NOT EXISTS hosting ( "hosting": """CREATE TABLE IF NOT EXISTS hosting (
id SERIAL, id BIGINT AUTO_INCREMENT PRIMARY KEY,
Name varchar(255), Name VARCHAR(255),
Capacity INT, Capacity INT,
reservedBy varchar(255) reservedBy VARCHAR(255)
);""", );""",
"santa": """CREATE TABLE IF NOT EXISTS santa ( "santa": """CREATE TABLE IF NOT EXISTS santa (
Name varchar(255), Name varchar(255),
@@ -28,19 +28,13 @@ STARTUP_TABLE_CREATION_QUERIES = {
} }
INJECT_TABLE_CREATION_QUERIES = { INJECT_TABLE_CREATION_QUERIES = {
"hosting": """ "hosting": """
INSERT INTO hosting (Name, Capacity, reservedBy) INSERT IGNORE INTO hosting (Name, Capacity, reservedBy) VALUES
SELECT name, capacity, reservedBy FROM ( ('Матрац 160cм', 2, ''),
SELECT 'Матрац 160см' AS name, 2 AS capacity, '' AS reservedBy ('Кровать 120cм', 2, ''),
UNION ALL ('Матрац 90cм', 1, ''),
SELECT 'Кровать 120см', 2, '' ('Диван', 1, '');
UNION ALL """
SELECT 'Матрац 90см', 1, ''
UNION ALL
SELECT 'Диван', 1, ''
) AS temp
WHERE NOT EXISTS (SELECT 1 FROM hosting WHERE Name = temp.name);
""",
} }
class Severity(Enum): class Severity(Enum):
@@ -61,7 +55,6 @@ class DBClient:
self.pool = self.create_pool() # Create a connection pool self.pool = self.create_pool() # Create a connection pool
self.initialize_database() self.initialize_database()
#self.initialize_secret_santa() # Initialize Secret Santa
def validate_env_variables(self): def validate_env_variables(self):
if not self.db_server or not self.db_port or not self.password or not self.database: if not self.db_server or not self.db_port or not self.password or not self.database:
@@ -84,56 +77,6 @@ class DBClient:
self.query(STARTUP_TABLE_CREATION_QUERIES['sessions']) self.query(STARTUP_TABLE_CREATION_QUERIES['sessions'])
self.query(STARTUP_TABLE_CREATION_QUERIES['hosting']) self.query(STARTUP_TABLE_CREATION_QUERIES['hosting'])
self.query(INJECT_TABLE_CREATION_QUERIES['hosting']) self.query(INJECT_TABLE_CREATION_QUERIES['hosting'])
def initialize_secret_santa(self):
table_exists = self.query("SHOW TABLES LIKE 'santa';")
if not table_exists:
self.query(STARTUP_TABLE_CREATION_QUERIES['santa'])
count_query = self.query('SELECT COUNT(*) FROM santa;')
if count_query[0][0] > 0:
self.app.logger.warning('The santa table is not empty. No assignments will be made.')
return
attendees = self.query('SELECT Name FROM users WHERE Attendance = 1;')
if not attendees:
return
attendees = [user[0] for user in attendees]
couples = [("Тюлень", "Тюлениха"), ("Медведь", "Ксения")]
max_attempts = 1000
for attempt in range(max_attempts):
shuffled_attendees = attendees.copy()
random.shuffle(shuffled_attendees)
santa_assignments = {}
valid = True
for index, user in enumerate(shuffled_attendees):
prev_user = shuffled_attendees[index - 1]
next_user = shuffled_attendees[(index + 1) % len(shuffled_attendees)]
if any(user in couple and (prev_user in couple or next_user in couple) for couple in couples):
valid = False
break
santa_assignments[user] = prev_user
if valid:
break
else:
self.app.logger.warning('Could not find valid Santa assignments after multiple attempts.')
return
self.app.logger.info(f'Santa assignments: {santa_assignments}')
for user, santa in santa_assignments.items():
self.query('INSERT INTO santa (Name, Santa) VALUES (%s, %s);', (user, santa))
def query(self, query_str, params=None): def query(self, query_str, params=None):

View File

@@ -164,65 +164,3 @@ def registerUserEndpoints(app, database):
except Exception as e: except Exception as e:
return jsonify(success=False, message=str(e)), 500 return jsonify(success=False, message=str(e)), 500
@app.route('/users/wishlist', methods=['PUT'])
def update_wishlist():
data = request.json
token = data.get('token')
wishlist_url = data.get('wishlist')
if wishlist_url is None:
return jsonify(success=False, message="Wishlist URL is required"), 400
query_session = "SELECT * FROM sessions WHERE Token=%s"
try:
result = database.query(query_session, params=(token,))
if not result:
return jsonify(success=False, message="Token is invalid or expired"), 401
user_name = result[0][1]
wishlist_query = "UPDATE users SET WishListUrl = %s WHERE Name = %s"
update_result = database.query(wishlist_query, params=(wishlist_url, user_name))
return jsonify(success=True, message="WishListUrl updated successfully"), 200
except Exception as e:
return jsonify(success=False, message=str(e)), 500
@app.route('/users/santa', methods=['GET'])
def get_santainfo():
token = request.args.get('token')
if not token:
return jsonify(success=False, message="Token is required"), 400
query_session = "SELECT * FROM sessions WHERE Token=%s"
try:
result = database.query(query_session, params=(token,))
if not result:
return jsonify(success=False, message="Token is invalid or expired"), 401
user_name = result[0][1]
santa_query = "SELECT Name FROM santa WHERE Santa = %s"
santa_result = database.query(santa_query, params=(user_name,))
if not santa_result:
return jsonify(success=False, message=f"User's {user_name} Santa info not found"), 404
santa_to = santa_result[0][0]
wishlist_query = "SELECT WishListUrl FROM users WHERE Name = %s"
wishlist_result = database.query(wishlist_query, params=(santa_to,))
santa_info = {
"santa_to": santa_to,
"wishlist": wishlist_result[0][0]
}
return jsonify(success=True, santa_info=santa_info), 200
except Exception as e:
return jsonify(success=False, message=str(e)), 500

View File

@@ -42,7 +42,7 @@
body { body {
background-color: #ffffff; background-color: #ffffff;
/* Light background for contrast */ /* Light background for contrast */
background-image: url('./assets/snowflakes.png'); background-image: url('./assets/leafs.png');
/* Background image */ /* Background image */
background-size: cover; background-size: cover;
/* Cover the entire screen */ /* Cover the entire screen */
@@ -114,7 +114,7 @@ section {
/* Festive Buttons */ /* Festive Buttons */
button { button {
background-color: #b77de5; background-color: #b5bb08;
/* Purple with a slight festive flair */ /* Purple with a slight festive flair */
color: white; color: white;
border: none; border: none;
@@ -126,7 +126,7 @@ button {
} }
button:hover { button:hover {
background-color: #9b6bb5; background-color: #48844e;
/* Darker purple on hover */ /* Darker purple on hover */
} }
@@ -177,7 +177,7 @@ table {
/* Table header styles */ /* Table header styles */
th { th {
background-color: #060698; background-color: #06984a;
/* Christmas red */ /* Christmas red */
color: white; color: white;
padding: 10px 15px; padding: 10px 15px;
@@ -218,7 +218,7 @@ table {
/* Add some festive decorations */ /* Add some festive decorations */
th::after { th::after {
content: '🎄'; content: '🌳';
/* Small Christmas tree icon in the header */ /* Small Christmas tree icon in the header */
margin-left: 10px; margin-left: 10px;
font-size: 1.2em; font-size: 1.2em;
@@ -234,8 +234,8 @@ td::before {
content: ''; content: '';
/* Placeholder for decoration */ /* Placeholder for decoration */
position: absolute; position: absolute;
background-image: url('path/to/snowflake-icon.png'); background-image: url('path/to/leaf-icon.png');
/* Snowflake icon */ /* leaf icon */
width: 16px; width: 16px;
/* Adjust as necessary */ /* Adjust as necessary */
height: 16px; height: 16px;
@@ -250,7 +250,7 @@ td::before {
nav { nav {
top: 0; /* Align it to the top */ top: 0; /* Align it to the top */
background-color: rgba(0, 42, 255, 0.6);; /* Background color */ background-color: #06984aef; /* Background color */
border-radius: 20px; border-radius: 20px;
z-index: 1000; /* Make sure it stays above other content */ z-index: 1000; /* Make sure it stays above other content */
padding: 1rem; padding: 1rem;
@@ -293,7 +293,7 @@ nav a:hover {
@media (max-width: 768px) { @media (max-width: 768px) {
.nav-toggle { .nav-toggle {
display: block; display: block;
background-color: rgba(0, 42, 255, 0.6); /* Button color */ background-color: rgba(255, 255, 0, 0.6); /* Button color */
border: none; border: none;
padding: 10px 20px; padding: 10px 20px;
cursor: pointer; cursor: pointer;

View File

@@ -4,7 +4,7 @@ import Greeting from './components/Greeting';
import Hosting from './components/Hosting'; import Hosting from './components/Hosting';
import InitialSetup from './components/InitialSetup'; import InitialSetup from './components/InitialSetup';
import Program from './components/Program'; import Program from './components/Program';
import Snowflakes from './components/Snowflakes'; import Leafs from './components/Leafs';
import { FullScreenLoading } from './components/Loading'; import { FullScreenLoading } from './components/Loading';
import SecretSanta from './components/SecretSanta'; import SecretSanta from './components/SecretSanta';
import Suggestions from './components/Suggestions'; import Suggestions from './components/Suggestions';
@@ -31,7 +31,7 @@ function App() {
return ( return (
<> <>
<FullScreenLoading /> <FullScreenLoading />
<Snowflakes /> <Leafs />
<InitialSetup /> <InitialSetup />
<button onClick={toggleNav} className="nav-toggle"> <button onClick={toggleNav} className="nav-toggle">
@@ -52,9 +52,6 @@ function App() {
<li> <li>
<a href="#suggestions">Пожелания</a> <a href="#suggestions">Пожелания</a>
</li> </li>
<li>
<a href="#santa">Secret Santa</a>
</li>
<li> <li>
<a href="#attendance-table">Кто празднует?</a> <a href="#attendance-table">Кто празднует?</a>
</li> </li>
@@ -76,9 +73,6 @@ function App() {
<div id="suggestions"> <div id="suggestions">
<Suggestions /> <Suggestions />
</div> </div>
<div id="santa">
<SecretSanta />
</div>
<div id="attendance-table"> <div id="attendance-table">
<AttendanceTable /> <AttendanceTable />
</div> </div>

View File

@@ -6,7 +6,7 @@
width: 100%; /* Full width of the viewport */ width: 100%; /* Full width of the viewport */
overflow-x: auto; /* Enables horizontal scrolling if necessary */ overflow-x: auto; /* Enables horizontal scrolling if necessary */
margin: 20px 0; /* Spacing above and below the container */ margin: 20px 0; /* Spacing above and below the container */
background-color: rgba(0, 42, 255, 0.6); background-color: #06984aef;
border-radius: 20px; border-radius: 20px;
} }

View File

@@ -0,0 +1,38 @@
.leafs {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* Make leafs non-interactive */
overflow: hidden; /* Hide overflow */
z-index: 998; /* Ensure leafs are above other content */
}
.leaf {
position: absolute;
top: -10%; /* Start above the top of the screen */
color: white; /* leaf color */
font-size: 1em; /* Size of the leaf; adjust as needed */
opacity: 0.6; /* Transparency */
animation: fall linear infinite; /* Apply the fall animation */
}
/* Falling animation */
@keyframes fall {
0% {
transform: translateX(0) translateY(0) rotate(0deg);/* Start position */
}
100% {
transform: translateX(-5vw) translateY(120vh) rotate(360deg); /* End position */
opacity: 0.1; /* Optional: fade out */
}
}
/* Randomize leaf size and animation */
.leaf:nth-child(1) { animation-duration: 6s; left: 10%; font-size: 0.8em;}
.leaf:nth-child(2) { animation-duration: 8s; left: 20%; font-size: 3em;}
.leaf:nth-child(3) { animation-duration: 5s; left: 30%; font-size: 4em;}
.leaf:nth-child(4) { animation-duration: 7s; left: 40%; font-size: 0.9em;}
.leaf:nth-child(5) { animation-duration: 10s; left: 50%; font-size: 2em;}
/* Add more child selectors for additional leafs */

View File

@@ -1,26 +1,26 @@
import React from 'react'; import React from 'react';
import './Snowflakes.css'; import './Leafs.css';
const Snowflakes: React.FC = () => { const Leafs: React.FC = () => {
// Adjust the number of snowflakes as needed // Adjust the number of leafs as needed
const snowflakeCount = Array.from({ length: 50 }); const leafCount = Array.from({ length: 50 });
return ( return (
<div className="snowflakes"> <div className="leafs">
{snowflakeCount.map((_, index) => ( {leafCount.map((_, index) => (
<div <div
key={index} key={index}
className="snowflake" className="leaf"
style={{ style={{
left: `${Math.random() * 100}vw`, // Random position across the full width left: `${Math.random() * 100}vw`, // Random position across the full width
animationDuration: `${Math.random() * 20 + 10}s`, // Random fall duration between 2s and 5s animationDuration: `${Math.random() * 20 + 10}s`, // Random fall duration between 2s and 5s
}} }}
> >
🍃
</div> </div>
))} ))}
</div> </div>
); );
}; };
export default Snowflakes; export default Leafs;

View File

@@ -1,10 +1,10 @@
.spinner { .spinner {
font-size: 100px; /* Adjust size as needed */ font-size: 100px; /* Adjust size as needed */
animation: spin 2s linear infinite; /* Spin animation */ animation: spin 2s linear infinite; /* Spin animation */
position: fixed; /* Keep the snowflake in a fixed position */ position: fixed; /* Keep the leaf in a fixed position */
top: 50%; /* Adjust vertical position */ top: 50%; /* Adjust vertical position */
left: 50%; /* Center horizontally */ left: 50%; /* Center horizontally */
transform: translateX(-50%); /* Center the snowflake */ transform: translateX(-50%); /* Center the leaf */
z-index: 10000; /* Ensure it's above the full-screen loading */ z-index: 10000; /* Ensure it's above the full-screen loading */
} }

View File

@@ -4,7 +4,7 @@ import './Loading.css'; // Import CSS for styling
export const Loading: React.FC = () => { export const Loading: React.FC = () => {
return ( return (
<div className="spinner"> <div className="spinner">
🎅🏻 🍺
</div> </div>
); );
}; };

View File

@@ -1,39 +0,0 @@
.snowflakes {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* Make snowflakes non-interactive */
overflow: hidden; /* Hide overflow */
z-index: 998; /* Ensure snowflakes are above other content */
}
.snowflake {
position: absolute;
top: -10%; /* Start above the top of the screen */
color: white; /* Snowflake color */
font-size: 1em; /* Size of the snowflake; adjust as needed */
opacity: 0.5; /* Transparency */
animation: fall linear infinite; /* Apply the fall animation */
}
/* Falling animation */
@keyframes fall {
0% {
transform: translateX(0) translateY(0); /* Start position */
}
100% {
transform: translateX(-5vw) translateY(120vh); /* End position */
opacity: 0.1; /* Optional: fade out */
}
}
/* Randomize snowflake size and animation */
.snowflake:nth-child(1) { animation-duration: 6s; left: 10%; font-size: 0.8em;}
.snowflake:nth-child(2) { animation-duration: 8s; left: 20%; font-size: 3em;}
.snowflake:nth-child(3) { animation-duration: 5s; left: 30%; font-size: 4em;}
.snowflake:nth-child(4) { animation-duration: 7s; left: 40%; font-size: 0.9em;}
.snowflake:nth-child(5) { animation-duration: 10s; left: 50%; font-size: 2em;}
/* Add more child selectors for additional snowflakes */