updates to ui, add donation page, update docs, add sharding
This commit is contained in:
parent
1c9a292af7
commit
0ed69852a3
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ node_modules/
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
register,log
|
register,log
|
||||||
|
donations.json
|
30
README.md
30
README.md
@ -12,18 +12,20 @@ Landing page for p0ntus mail
|
|||||||
```bash
|
```bash
|
||||||
mv docker-compose.yml.example docker-compose.yml
|
mv docker-compose.yml.example docker-compose.yml
|
||||||
```
|
```
|
||||||
3. Make the `self` script executable
|
3. Copy the example `donations.json`
|
||||||
```bash
|
```bash
|
||||||
chmod +x self
|
mv donations.json.example donations.json
|
||||||
```
|
```
|
||||||
4. Use `self` script to serve files into `public/` directory
|
4. Install dependencies
|
||||||
```bash
|
```bash
|
||||||
./self start
|
npm install
|
||||||
|
```
|
||||||
|
4. Start the server
|
||||||
|
```bash
|
||||||
|
node app.js
|
||||||
```
|
```
|
||||||
|
|
||||||
You will now have to use a server (NGINX, Apache2, etc.) to serve files from the `./public` directory. You may use the example `default.conf` with NGINX if you wish.
|
You will now have a fully functioning Node.js Express server, which will be running on port `3000`.
|
||||||
|
|
||||||
Make changes from the `./src` directory, and `self` will copy them over.
|
|
||||||
## With Docker
|
## With Docker
|
||||||
You can also use Docker to self-host pontus-mail's frontend. Make sure you have docker-compose or docker-compose-plugin installed on your system.
|
You can also use Docker to self-host pontus-mail's frontend. Make sure you have docker-compose or docker-compose-plugin installed on your system.
|
||||||
1. Clone the repo
|
1. Clone the repo
|
||||||
@ -35,17 +37,13 @@ You can also use Docker to self-host pontus-mail's frontend. Make sure you have
|
|||||||
```bash
|
```bash
|
||||||
mv docker-compose.yml.example docker-compose.yml
|
mv docker-compose.yml.example docker-compose.yml
|
||||||
```
|
```
|
||||||
3. Make the `self` script executable
|
3. Copy the example `donations.json`
|
||||||
```bash
|
```bash
|
||||||
chmod +x self
|
mv donations.json.example donations.json
|
||||||
```
|
```
|
||||||
4. Start Docker containers
|
4. Start and build Docker containers
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d
|
docker compose up -d --build
|
||||||
```
|
|
||||||
5. Use `self` script to serve files into `public/` directory
|
|
||||||
```bash
|
|
||||||
./self start
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You will now have a fully functioning NGINX server, serving the pontus-mail website from the `./public` directory. Make your changes in the `./src` directory, if any.
|
You will now have a fully functioning Node.js Express server, which will be running on the port specified in `docker-compose.yml`, and internally on port `3000`.
|
24
app.js
24
app.js
@ -1,9 +1,9 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
//const winston = require('winston');
|
//const winston = require('winston');
|
||||||
//const rateLimit = require('express-rate-limit');
|
//const rateLimit = require('express-rate-limit');
|
||||||
//const fs = require('fs');
|
|
||||||
|
|
||||||
//const logger = winston.createLogger({
|
//const logger = winston.createLogger({
|
||||||
// level: 'info',
|
// level: 'info',
|
||||||
@ -38,7 +38,7 @@ app.use(bodyParser.urlencoded({ extended: false }));
|
|||||||
app.use(express.static(path.join(__dirname, 'public')));
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.render('index');
|
res.render('index', { currentPage: 'home' });
|
||||||
});
|
});
|
||||||
|
|
||||||
//app.post('/register', registerLimiter, (req, res) => {
|
//app.post('/register', registerLimiter, (req, res) => {
|
||||||
@ -58,12 +58,24 @@ app.get('/', (req, res) => {
|
|||||||
// res.render('success');
|
// res.render('success');
|
||||||
//});
|
//});
|
||||||
|
|
||||||
app.get('/register', (req, res) => {
|
app.get('/services', (req, res) => {
|
||||||
res.render('register');
|
res.render('services', { currentPage: 'services' });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/services', (req, res) => {
|
app.get('/register', (req, res) => {
|
||||||
res.render('services');
|
res.render('register', { currentPage: 'register' });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/donate', (req, res) => {
|
||||||
|
const donations = JSON.parse(fs.readFileSync('donations.json', 'utf8'));
|
||||||
|
res.render('donate', {
|
||||||
|
currentPage: 'donate',
|
||||||
|
bitcoin: donations.bitcoin,
|
||||||
|
litecoin: donations.litecoin,
|
||||||
|
ethereum: donations.ethereum,
|
||||||
|
current: donations.current,
|
||||||
|
goal: donations.goal
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
@ -8,5 +8,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./register.log:/usr/src/app/register.log
|
- ./register.log:/usr/src/app/register.log
|
||||||
- ./exclusions.json:/usr/src/app/exclusions.json
|
- ./exclusions.json:/usr/src/app/exclusions.json
|
||||||
|
- ./donations.json:/usr/src/app/donations.json
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
7
donations.json.example
Normal file
7
donations.json.example
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"bitcoin": "bitcoinaddresshere",
|
||||||
|
"litecoin": "litecoinaddresshere",
|
||||||
|
"ethereum": "ethereumaddresshere",
|
||||||
|
"current": 0,
|
||||||
|
"goal": 55
|
||||||
|
}
|
26
src/donate.ejs
Normal file
26
src/donate.ejs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<%- include('shards/header', { title: 'Donate - p0ntus mail' }) %>
|
||||||
|
<div class="container">
|
||||||
|
<%- include('shards/nav', { currentPage: 'donate' }) %>
|
||||||
|
<i class="il mt-5">Current donation progress this month</i>
|
||||||
|
<hr>
|
||||||
|
<div class="progress mt-3">
|
||||||
|
<div class="progress-bar bg-dark" role="progressbar" style="width: <%= (current / goal) * 100 %>%;" aria-valuenow="<%= current %>" aria-valuemin="0" aria-valuemax="<%= goal %>">$<%= current %> / $<%= goal %></div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between mt-2">
|
||||||
|
<span><b>Current:</b> $<%= current %></span>
|
||||||
|
<span><b>Goal:</b> $<%= goal %></span>
|
||||||
|
</div>
|
||||||
|
<p>This goal represents the cost of the server and its operation, based on the bill from the previous month.</p>
|
||||||
|
<hr>
|
||||||
|
<i class="il mt-5">Donate with Cryptocurrency</i>
|
||||||
|
<hr>
|
||||||
|
<div class="text-start">
|
||||||
|
<h5><i class="fa-brands fa-bitcoin ico-sm" style="color: #f7931a;"></i> Bitcoin</h5>
|
||||||
|
<p><%= bitcoin %></p>
|
||||||
|
<h5><i class="fa-brands fa-ethereum ico-sm" style="color: #3c3c3d;"></i> Ethereum</h5>
|
||||||
|
<p><%= ethereum %></p>
|
||||||
|
<h5><i class="fa-solid fa-litecoin-sign ico-sm" style="color: #bebebe;"></i> Litecoin</h5>
|
||||||
|
<p><%= litecoin %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%- include('shards/footer') %>
|
@ -1,34 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<%- include('shards/header', { title: 'p0ntus mail' }) %>
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>p0ntus mail</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
||||||
<link rel="stylesheet" href="css/main.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1><i class="fa-solid fa-envelope text-dark ico"></i> p0ntus mail.</h1>
|
<%- include('shards/nav', { currentPage: 'home' }) %>
|
||||||
<h3>simple, mindful, secure email.</h3>
|
<i class="il mt-5">Welcome to p0ntus mail</i>
|
||||||
<nav class="nav justify-content-center">
|
<hr>
|
||||||
<a href="#" class="nav-link text-dark"><b>Home</b></a>
|
<p>Hello, and thanks for checking our my personal email server.</p>
|
||||||
<a href="/services" class="nav-link text-dark">Services</a>
|
<p>If you're just curious, check out the "Services" page. If you'd like to sign up, simply use the "Register" link.</p>
|
||||||
</nav>
|
|
||||||
<i class="il mt-5">Where can I direct your request?</i>
|
<i class="il mt-5">Where can I direct your request?</i>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="text-start">
|
<div class="text-start">
|
||||||
<p class="il"><i>If you aren't a current user</i></p>
|
<h5><i>If you aren't a current user</i></h4>
|
||||||
<a href="/register" class="btn bg-dark text-white"><i class="fa-solid fa-user-plus ico-sm"></i> Register</a>
|
<a href="/register" class="btn bg-dark text-white mt-2"><i class="fa-solid fa-user-plus ico-sm"></i> Register</a>
|
||||||
<hr>
|
<hr>
|
||||||
<p class="il"><i>If you are a current user</i></p>
|
<h5><i>If you are a current user</i></h4>
|
||||||
<a href="/SOGo" class="btn bg-dark text-white"><i class="fa-solid fa-envelope ico-sm"></i> Webmail</a>
|
<a href="/SOGo" class="btn bg-dark text-white mt-2"><i class="fa-solid fa-envelope ico-sm"></i> Webmail</a>
|
||||||
<a href="https://user.p0ntus.com" class="btn bg-dark text-white"><i class="fa-solid fa-user ico-sm"></i> Account</a>
|
<a href="https://user.p0ntus.com" class="btn bg-dark text-white mt-2"><i class="fa-solid fa-user ico-sm"></i> Account</a>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<%- include('shards/footer') %>
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,30 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<%- include('shards/header', { title: 'Register - p0ntus mail' }) %>
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Register - p0ntus mail</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/css/fontawesome.min.css" integrity="sha384-NvKbDTEnL+A8F/AA5Tc5kmMLSJHUO868P+lDtTpJIeQdGYaUIuLr4lVGOEA1OcMy" crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href="css/main.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Register</h1>
|
<%- include('shards/nav', { currentPage: 'register' }) %>
|
||||||
<h3>Registration is done via email</h3>
|
<i class="il mt-5">Register</i>
|
||||||
<i>Please contact <a href="mailto:signup@p0ntus.com">signup<i class="fa-solid fa-at"></i>p0ntus.com</a> with the following info:</i>
|
|
||||||
<hr>
|
<hr>
|
||||||
<ul class="list-group">
|
<i>Please contact <a href="mailto:signup@p0ntus.com">signup<i class="fa-solid fa-at"></i>p0ntus.com</a> with the following info:</i>
|
||||||
|
<ul class="list-group mt-3">
|
||||||
<li class="list-group-item">Name that goes in email header (full name/username/alias)</li>
|
<li class="list-group-item">Name that goes in email header (full name/username/alias)</li>
|
||||||
<li class="list-group-item">Desired email address (e.g., yourname@p0ntus.com)</li>
|
<li class="list-group-item">Desired email address (e.g., yourname@p0ntus.com)</li>
|
||||||
<li class="list-group-item">Reason for wanting an email</li>
|
<li class="list-group-item">Reason for wanting an email</li>
|
||||||
<li class="list-group-item">Telegram username</li>
|
<li class="list-group-item">Telegram username</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr>
|
|
||||||
<a href="/" class="btn bg-dark text-white">Return to Home</a>
|
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<%- include('shards/footer') %>
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,25 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<%- include('shards/header', { title: 'Services - p0ntus mail' }) %>
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Services - p0ntus mail</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
||||||
<link rel="stylesheet" href="css/main.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1><i class="fa-solid fa-envelope text-dark ico"></i> p0ntus mail.</h1>
|
<%- include('shards/nav', { currentPage: 'services' }) %>
|
||||||
<h3>simple, mindful, secure email.</h3>
|
|
||||||
<nav class="nav justify-content-center">
|
|
||||||
<a href="/" class="nav-link text-dark">Home</a>
|
|
||||||
<a href="#" class="nav-link text-dark"><b>Services</b></a>
|
|
||||||
</nav>
|
|
||||||
<i class="il mt-5">What we do</i>
|
<i class="il mt-5">What we do</i>
|
||||||
<hr>
|
<hr>
|
||||||
|
<p class="text-start">p0ntus mail is an email server I personally host ana manage, avaliable free of charge to the public. p0ntus mail is free, and powered by user donations.</p>
|
||||||
|
<p class="text-start">Here is what we have to offer you:</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mb-4">
|
<div class="col-md-6 mb-4">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@ -54,7 +39,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<i class="il mt-3">What you get</i>
|
||||||
|
<hr>
|
||||||
|
<p>Upon creating your account, you will be allocated an account with the following:</p>
|
||||||
|
<ul class="list-group text-start">
|
||||||
|
<li class="list-group-item">4000 MB storage</li>
|
||||||
|
<li class="list-group-item">Webmail access</li>
|
||||||
|
<li class="list-group-item">IMAP/SMTP access (soon)</li>
|
||||||
|
<li class="list-group-item">Spam protection</li>
|
||||||
|
<li class="list-group-item">5 outgoing messages per hour</li>
|
||||||
|
</ul>
|
||||||
|
<p class="text-start mt-3">You may request for additional storage, or increased account limits by contacting <a href="mailto:admin@p0ntus.com">admin<i class="fa-solid fa-at p"></i>p0ntus.com</a>. We operate under a "fair use" policy.</p>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<%- include('shards/footer') %>
|
||||||
</body>
|
|
||||||
</html>
|
|
3
src/shards/footer.ejs
Normal file
3
src/shards/footer.ejs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
src/shards/header.ejs
Normal file
14
src/shards/header.ejs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap" rel="stylesheet">
|
||||||
|
<script src="https://kit.fontawesome.com/50495cc725.js" crossorigin="anonymous"></script>
|
||||||
|
<link rel="stylesheet" href="css/main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
24
src/shards/nav.ejs
Normal file
24
src/shards/nav.ejs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<h1><i class="fa-solid fa-envelope text-dark ico"></i> p0ntus mail.</h1>
|
||||||
|
<h3>simple, mindful, secure email.</h3>
|
||||||
|
<nav class="nav justify-content-center">
|
||||||
|
<% if (currentPage === 'home') { %>
|
||||||
|
<span class="nav-link text-dark"><b>Home</b></span>
|
||||||
|
<% } else { %>
|
||||||
|
<a href="/" class="nav-link text-dark">Home</a>
|
||||||
|
<% } %>
|
||||||
|
<% if (currentPage === 'services') { %>
|
||||||
|
<span class="nav-link text-dark"><b>Services</b></span>
|
||||||
|
<% } else { %>
|
||||||
|
<a href="/services" class="nav-link text-dark">Services</a>
|
||||||
|
<% } %>
|
||||||
|
<% if (currentPage === 'register') { %>
|
||||||
|
<span class="nav-link text-dark"><b>Register</b></span>
|
||||||
|
<% } else { %>
|
||||||
|
<a href="/register" class="nav-link text-dark">Register</a>
|
||||||
|
<% } %>
|
||||||
|
<% if (currentPage === 'donate') { %>
|
||||||
|
<span class="nav-link text-dark"><b>Donate</b></span>
|
||||||
|
<% } else { %>
|
||||||
|
<a href="/donate" class="nav-link text-dark">Donate</a>
|
||||||
|
<% } %>
|
||||||
|
</nav>
|
@ -1,15 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<%- include('shards/header', { title: 'p0ntus mail' }) %>
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Success - p0ntus mail</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap" rel="stylesheet"> <link rel="stylesheet" href="css/main.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1><i class="fa-solid fa-check-circle text-success"></i> Success</h1>
|
<h1><i class="fa-solid fa-check-circle text-success"></i> Success</h1>
|
||||||
<h3>Your registration request has been submitted</h3>
|
<h3>Your registration request has been submitted</h3>
|
||||||
@ -17,6 +6,4 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<a href="/" class="btn bg-dark text-white"><i class="fa-solid fa-home ico-sm"></i> Return to Home</a>
|
<a href="/" class="btn bg-dark text-white"><i class="fa-solid fa-home ico-sm"></i> Return to Home</a>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<%- include('shards/footer') %>
|
||||||
</body>
|
|
||||||
</html>
|
|
Reference in New Issue
Block a user