First part of backend rework
- Added the base data structure for the new database - Added the new routes for the new database - Reworked the users endpoints
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
PORT=3000
|
||||
DOMAIN="http://localhost:3000"
|
||||
DATABASE_HOST="127.0.0.1"
|
||||
DATABASE_NAME=hsp-gdh
|
||||
DATABASE_USER=hsp-gdh
|
||||
DATABASE_PASSWORD=""
|
||||
JWT_SECRET=""
|
||||
PORT=
|
||||
SMTP=
|
||||
MAIL=
|
||||
MAIL_PASS=
|
||||
@@ -46,5 +46,8 @@
|
||||
"space-unary-ops": "error",
|
||||
"spaced-comment": "error",
|
||||
"yoda": "error"
|
||||
},
|
||||
"globals": {
|
||||
"Bun": false
|
||||
}
|
||||
}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -131,3 +131,9 @@ dist
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# logs
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# token
|
||||
token/
|
||||
409
database.sql
409
database.sql
@@ -10,128 +10,28 @@ GRANT ALL PRIVILEGES ON airjet.* TO 'hsp-gdh'@'%';
|
||||
|
||||
USE `hsp-gdh`;
|
||||
|
||||
CREATE TABLE pilots (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
first_name VARCHAR(255) NOT NULL,
|
||||
last_name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
phone VARCHAR(20) NOT NULL,
|
||||
license_number VARCHAR(255) NOT NULL,
|
||||
license_expiry DATE NOT NULL,
|
||||
salary DECIMAL(10, 2) NOT NULL DEFAULT 0.0,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE airplanes (
|
||||
CREATE TABLE roles (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(255) NOT NULL,
|
||||
manufacturer VARCHAR(255) NOT NULL,
|
||||
capacity INT NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
location VARCHAR(255),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE airlines (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
code VARCHAR(2) NOT NULL,
|
||||
logo VARCHAR(255),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE airports (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
code VARCHAR(3) NOT NULL,
|
||||
city VARCHAR(255) NOT NULL,
|
||||
country VARCHAR(255) NOT NULL,
|
||||
latitude FLOAT NOT NULL,
|
||||
longitude FLOAT NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE flights (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
airline_id INT UNSIGNED NOT NULL,
|
||||
pilot_id INT UNSIGNED NOT NULL,
|
||||
flight_no VARCHAR(10) NOT NULL,
|
||||
origin_id INT UNSIGNED NOT NULL,
|
||||
destination_id INT UNSIGNED NOT NULL,
|
||||
departure_time DATETIME NOT NULL,
|
||||
arrival_time DATETIME NOT NULL,
|
||||
duration_minutes INT NOT NULL,
|
||||
price_economy DECIMAL(10,2) NOT NULL,
|
||||
price_business DECIMAL(10,2) NOT NULL,
|
||||
price_first_class DECIMAL(10,2) NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
user_bitfield INT UNSIGNED NOT NULL,
|
||||
role_bitfield INT UNSIGNED NOT NULL,
|
||||
verification_code_bitfield INT UNSIGNED NOT NULL,
|
||||
ban_bitfield INT UNSIGNED NOT NULL,
|
||||
patient_bitfield INT UNSIGNED NOT NULL,
|
||||
doctor_bitfield INT UNSIGNED NOT NULL,
|
||||
service_bitfield INT UNSIGNED NOT NULL,
|
||||
company_bitfield INT UNSIGNED NOT NULL,
|
||||
hospital_bitfield INT UNSIGNED NOT NULL,
|
||||
room_bitfield INT UNSIGNED NOT NULL,
|
||||
appointment_bitfield INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fl_airline_id
|
||||
FOREIGN KEY (airline_id)
|
||||
REFERENCES airlines(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
CONSTRAINT fl_pilot_id
|
||||
FOREIGN KEY (pilot_id)
|
||||
REFERENCES pilots(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
CONSTRAINT fl_origin_id
|
||||
FOREIGN KEY (origin_id)
|
||||
REFERENCES airports(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
CONSTRAINT fl_destination_id
|
||||
FOREIGN KEY (destination_id)
|
||||
REFERENCES airports(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE
|
||||
UNIQUE INDEX r_name_idx (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE user_types (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE INDEX ut_name_idx (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO user_types (name) VALUES ('unverified'), ('customer'), ('support'), ('pilote'), ('staff'), ('admin');
|
||||
|
||||
CREATE TABLE permissions (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE INDEX p_name_idx (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO permissions (name) VALUES
|
||||
('view_users'), ('add_users'), ('edit_users'), ('delete_users'),
|
||||
('view_flights'), ('add_flights'), ('edit_flights'), ('delete_flights'),
|
||||
('view_airlines'), ('add_airlines'), ('edit_airlines'), ('delete_airlines'),
|
||||
('view_airplanes'), ('add_airplanes'), ('edit_airplanes'), ('delete_airplanes'),
|
||||
('view_airports'), ('add_airports'), ('edit_airports'), ('delete_airports'),
|
||||
('view_seats'), ('add_seats'), ('edit_seats'), ('delete_seats'),
|
||||
('view_pilots'), ('add_pilots'), ('edit_pilots'), ('delete_pilots');
|
||||
|
||||
CREATE TABLE user_type_permissions (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_type_id INT UNSIGNED NOT NULL,
|
||||
permission_id INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT utp_user_type_id
|
||||
FOREIGN KEY (user_type_id)
|
||||
REFERENCES user_types(id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE,
|
||||
CONSTRAINT utp_permission_id
|
||||
FOREIGN KEY (permission_id)
|
||||
REFERENCES permissions(id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE,
|
||||
UNIQUE INDEX utp_user_type_permission_idx (user_type_id, permission_id)
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO roles (name, user_bitfield, role_bitfield, verification_code_bitfield, ban_bitfield, patient_bitfield, doctor_bitfield, service_bitfield, company_bitfield, hospital_bitfield, room_bitfield, appointment_bitfield) VALUES
|
||||
('Admin', 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7),
|
||||
('Doctor', 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0),
|
||||
('Patient', 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0);
|
||||
|
||||
CREATE TABLE users (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
@@ -140,19 +40,31 @@ CREATE TABLE users (
|
||||
username VARCHAR(64) NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(128) NOT NULL,
|
||||
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
phone VARCHAR(32) DEFAULT 'None',
|
||||
user_type_id INT UNSIGNED NOT NULL,
|
||||
is_banned BOOLEAN NOT NULL DEFAULT 0,
|
||||
phone_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT u_user_type_id
|
||||
FOREIGN KEY (user_type_id)
|
||||
REFERENCES user_types(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ur_user_type_idx (user_type_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE user_email_verifications (
|
||||
CREATE TABLE user_roles (
|
||||
user_id INT UNSIGNED NOT NULL,
|
||||
role_id INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
CONSTRAINT ur_user_id
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ur_user_id_idx (user_id),
|
||||
CONSTRAINT ur_role_id
|
||||
FOREIGN KEY (role_id)
|
||||
REFERENCES roles(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ur_role_id_idx (role_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE verification_codes (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id INT UNSIGNED NOT NULL,
|
||||
verification_code VARCHAR(255),
|
||||
@@ -167,108 +79,169 @@ CREATE TABLE user_email_verifications (
|
||||
INDEX mv_user_id_idx (user_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE seats (
|
||||
CREATE TABLE bans (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id INT UNSIGNED,
|
||||
flight_id INT UNSIGNED NOT NULL,
|
||||
place_no INT UNSIGNED NOT NULL,
|
||||
class VARCHAR(32) NOT NULL,
|
||||
bought_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id INT UNSIGNED NOT NULL,
|
||||
reason TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT ps_user_id
|
||||
CONSTRAINT bn_user_id
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
CONSTRAINT ps_flight_id
|
||||
FOREIGN KEY (flight_id)
|
||||
REFERENCES flights(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ps_user_id_idx (user_id),
|
||||
INDEX ps_flight_id_idx (flight_id)
|
||||
INDEX bn_user_id_idx (user_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO pilots (id, first_name, last_name, email, phone, license_number, license_expiry, salary, status) VALUES
|
||||
(1, 'John', 'Doe', 'john.doe@example.com', '555-1234', '1234-5678', '2025-06-30', 75000.00, 'Active'),
|
||||
(2, 'Jane', 'Smith', 'jane.smith@example.com', '555-5678', '9876-5432', '2024-12-31', 80000.00, 'Active'),
|
||||
(3, 'Bob', 'Johnson', 'bob.johnson@example.com', '555-7890', '3456-7890', '2023-09-30', 70000.00, 'Inactive'),
|
||||
(4, 'Alice', 'Lee', 'alice.lee@example.com', '555-2345', '5678-1234', '2024-03-31', 85000.00, 'Active'),
|
||||
(5, 'David', 'Nguyen', 'david.nguyen@example.com', '555-5678', '1234-5678', '2023-12-31', 75000.00, 'Active'),
|
||||
(6, 'Maria', 'Garcia', 'maria.garcia@example.com', '555-7890', '9876-5432', '2024-06-30', 70000.00, 'Active'),
|
||||
(7, 'Mohammed', 'Ali', 'mohammed.ali@example.com', '555-2345', '3456-7890', '2025-09-30', 85000.00, 'Inactive'),
|
||||
(8, 'Sofia', 'Martinez', 'sofia.martinez@example.com', '555-3456', '5678-1234', '2022-03-31', 80000.00, 'Active');
|
||||
CREATE TABLE doctors (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id INT UNSIGNED NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
phone VARCHAR(20) NOT NULL,
|
||||
speciality VARCHAR(255) NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT dt_user_id
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX dt_user_id_idx (user_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO airplanes (id, name, type, manufacturer, capacity, status, location) VALUES
|
||||
(1, 'Boeing 747', 'Jet', 'Boeing', 660, 'Active', 'Los Angeles'),
|
||||
(2, 'Airbus A320', 'Jet', 'Airbus', 180, 'Active', 'New York'),
|
||||
(3, 'Embraer E175', 'Jet', 'Embraer', 78, 'Inactive', 'Miami'),
|
||||
(4, 'Boeing 737', 'Jet', 'Boeing', 160, 'Active', 'Chicago'),
|
||||
(5, 'Airbus A330', 'Jet', 'Airbus', 440, 'Active', 'Paris'),
|
||||
(6, 'Bombardier CRJ900', 'Jet', 'Bombardier', 88, 'Active', 'Montreal'),
|
||||
(7, 'Boeing 777', 'Jet', 'Boeing', 396, 'Inactive', 'London'),
|
||||
(8, 'Airbus A380', 'Jet', 'Airbus', 853, 'Active', 'Dubai'),
|
||||
(9, 'Embraer E190', 'Jet', 'Embraer', 114, 'Active', 'Buenos Aires'),
|
||||
(10, 'Boeing 787', 'Jet', 'Boeing', 335, 'Active', 'Tokyo'),
|
||||
(11, 'Boeing 747-8', 'Jet', 'Boeing', 605, 'Active', 'Hong Kong'),
|
||||
(12, 'Airbus A350', 'Jet', 'Airbus', 440, 'Active', 'Dublin'),
|
||||
(13, 'Embraer E195', 'Jet', 'Embraer', 124, 'Inactive', 'Rio de Janeiro'),
|
||||
(14, 'Boeing 737 MAX', 'Jet', 'Boeing', 230, 'Active', 'Seattle'),
|
||||
(15, 'Airbus A321', 'Jet', 'Airbus', 236, 'Active', 'Shanghai');
|
||||
CREATE TABLE patients (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id INT UNSIGNED NOT NULL,
|
||||
date_of_birth DATE NOT NULL,
|
||||
gender ENUM('M', 'F', 'O') NOT NULL,
|
||||
address VARCHAR(255) NOT NULL,
|
||||
social_security_number VARCHAR(128) NOT NULL,
|
||||
insurance_number VARCHAR(128) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO airlines (id, name, code, logo) VALUES
|
||||
(1, 'Delta Air Lines', 'DL', 'https://www.delta.com/content/dam/delta-com/brand-icons/Delta_Icon_blue_72.png'),
|
||||
(2, 'American Airlines', 'AA', 'https://www.aa.com/content/dam/aa-com/logo-web/aa-logo-blue-and-red-horz.png'),
|
||||
(3, 'United Airlines', 'UA', 'https://www.united.com/web/en-US/content/images/global/header/header-united-logo.png'),
|
||||
(4, 'Southwest Airlines', 'WN', 'https://www.southwest.com/etc/designs/southwest/v2/images/swa-logo--mod.svg'),
|
||||
(5, 'Alaska Airlines', 'AS', 'https://www.alaskaair.com/content/dam/alaskaair/logo/2016/alaska-airlines-horiz-white-blue-1x.png'),
|
||||
(6, 'JetBlue Airways', 'B6', 'https://www.jetblue.com/etc/designs/jetblue/clientlibs/dist/images/svg/jetblue-logo.svg'),
|
||||
(7, 'Spirit Airlines', 'NK', 'https://www.spirit.com/images/spirit-logo.png'),
|
||||
(8, 'Frontier Airlines', 'F9', 'https://www.flyfrontier.com/etc/designs/frontier-airlines/clientlibs/dist/images/f9-logo-horz.svg'),
|
||||
(9, 'Air France', 'AF', 'https://www.airfrance.com/etc/designs/airfrance/clientlibs/dist/images/global/logo/airfrance-logo-blue.svg'),
|
||||
(10, 'Transavia France', 'TO', 'https://www.transavia.com/content/dam/airlines/tv/fra/fr/common/img/logo.svg'),
|
||||
(11, 'EasyJet France', 'U2', 'https://www.easyjet.com/etc/designs/easyjet/clientlibs/dist/images/logo.svg'),
|
||||
(12, 'Corsair International', 'SS', 'https://www.corsair.fr/etc/designs/corsair/clientlibs/dist/images/logo.svg'),
|
||||
(13, 'XL Airways France', 'SE', 'https://www.xl.com/assets/images/XL-logo.png'),
|
||||
(14, 'Aigle Azur', 'ZI', 'https://www.aigle-azur.com/site/sites/all/themes/aigle-azur/images/logo-aigle-azur-160x80.png');
|
||||
CREATE TABLE services (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
price DECIMAL(10, 2) NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO airports (id, name, code, city, country, latitude, longitude) VALUES
|
||||
(1, 'John F. Kennedy International Airport', 'JFK', 'New York', 'United States', 40.6413, -73.7781),
|
||||
(2, 'Los Angeles International Airport', 'LAX', 'Los Angeles', 'United States', 33.9416, -118.4085),
|
||||
(3, 'London Heathrow Airport', 'LHR', 'London', 'United Kingdom', 51.4700, -0.4543),
|
||||
(4, 'Paris-Charles de Gaulle Airport', 'CDG', 'Paris', 'France', 49.0097, 2.5479),
|
||||
(5, 'Tokyo Haneda Airport', 'HND', 'Tokyo', 'Japan', 35.5532, 139.7818),
|
||||
(6, 'Dubai International Airport', 'DXB', 'Dubai', 'United Arab Emirates', 25.2528, 55.3644),
|
||||
(7, 'Sydney Kingsford Smith Airport', 'SYD', 'Sydney', 'Australia', -33.9461, 151.1772),
|
||||
(8, 'São Paulo-Guarulhos International Airport', 'GRU', 'São Paulo', 'Brazil', -23.4356, -46.4731),
|
||||
(9, 'Jomo Kenyatta International Airport', 'NBO', 'Nairobi', 'Kenya', -1.3192, 36.9258),
|
||||
(10, 'Cairo International Airport', 'CAI', 'Cairo', 'Egypt', 30.1111, 31.4139),
|
||||
(11, 'Paris Orly Airport', 'ORY', 'Paris', 'France', 48.7262, 2.3650),
|
||||
(12, 'Nice Côte d''Azur Airport', 'NCE', 'Nice', 'France', 43.6584, 7.2157),
|
||||
(13, 'Marseille Provence Airport', 'MRS', 'Marseille', 'France', 43.4393, 5.2214),
|
||||
(14, 'Lyon-Saint-Exupéry Airport', 'LYS', 'Lyon', 'France', 45.7216, 5.0790),
|
||||
(15, 'Bordeaux-Mérignac Airport', 'BOD', 'Bordeaux', 'France', 44.8283, -0.7156),
|
||||
(16, 'Toulouse-Blagnac Airport', 'TLS', 'Toulouse', 'France', 43.6356, 1.3678),
|
||||
(17, 'Nantes Atlantique Airport', 'NTE', 'Nantes', 'France', 47.1567, -1.6114),
|
||||
(18, 'Strasbourg Airport', 'SXB', 'Strasbourg', 'France', 48.5442, 7.6277),
|
||||
(19, 'Lille Airport', 'LIL', 'Lille', 'France', 50.5633, 3.0897),
|
||||
(20, 'Brest Bretagne Airport', 'BES', 'Brest', 'France', 48.4472, -4.4228),
|
||||
(21, 'Vienna International Airport', 'VIE', 'Vienna', 'Austria', 48.1197, 16.5667),
|
||||
(22, 'Zürich Airport', 'ZRH', 'Zürich', 'Switzerland', 47.4502, 8.5618),
|
||||
(23, 'Amsterdam Airport Schiphol', 'AMS', 'Amsterdam', 'Netherlands', 52.3081, 4.7642),
|
||||
(24, 'Frankfurt Airport', 'FRA', 'Frankfurt', 'Germany', 50.0379, 8.5622),
|
||||
(25, 'Barcelona-El Prat Airport', 'BCN', 'Barcelona', 'Spain', 41.2974, 2.0833),
|
||||
(26, 'Adolfo Suárez Madrid-Barajas Airport', 'MAD', 'Madrid', 'Spain', 40.4936, -3.5668),
|
||||
(27, 'Leonardo da Vinci-Fiumicino Airport', 'FCO', 'Rome', 'Italy', 41.8003, 12.2388),
|
||||
(28, 'Stockholm Arlanda Airport', 'ARN', 'Stockholm', 'Sweden', 59.6519, 17.9186);
|
||||
CREATE TABLE service_doctors (
|
||||
service_id INT UNSIGNED NOT NULL,
|
||||
doctor_id INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (service_id, doctor_id),
|
||||
CONSTRAINT sd_service_id
|
||||
FOREIGN KEY (service_id)
|
||||
REFERENCES services(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX sd_service_id_idx (service_id),
|
||||
CONSTRAINT sd_doctor_id
|
||||
FOREIGN KEY (doctor_id)
|
||||
REFERENCES doctors(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX sd_doctor_id_idx (doctor_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO flights (id, airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status) VALUES
|
||||
(1, 1, 1, 'BA123', 1, 2, '2023-03-15 08:00:00', '2023-03-15 10:00:00', 120, 100, 200, 300, 'scheduled'),
|
||||
(2, 2, 2, 'AF456', 2, 3, '2023-03-16 14:00:00', '2023-03-16 16:30:00', 150, 80, 150, 250, 'scheduled'),
|
||||
(3, 3, 3, 'LH789', 4, 5, '2023-03-17 09:30:00', '2023-03-17 12:00:00', 150, 90, 170, 280, 'scheduled'),
|
||||
(4, 1, 4, 'BA345', 2, 5, '2023-03-18 07:00:00', '2023-03-18 10:00:00', 180, 120, 240, 400, 'scheduled'),
|
||||
(5, 4, 5, 'EZY678', 3, 1, '2023-03-19 11:00:00', '2023-03-19 13:00:00', 120, 60, 120, 200, 'scheduled'),
|
||||
(6, 2, 6, 'AF901', 5, 6, '2023-03-20 16:30:00', '2023-03-20 19:00:00', 150, 100, 200, 350, 'scheduled');
|
||||
CREATE TABLE companies (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
code VARCHAR(2) NOT NULL,
|
||||
logo VARCHAR(255),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO `user_type_permissions` (`user_type_id`, `permission_id`) VALUES
|
||||
('6', '1'),('6', '2'),('6', '3'),('6', '4'),('6', '5'),('6', '6'),('6', '7'),('6', '8'),('6', '9'),('6', '10'),('6', '11'),('6', '12'),('6', '13'),('6', '14'),('6', '15'),('6', '16'),('6', '17'),('6', '18'),('6', '19'),('6', '20'),('6', '21'),('6', '22'),('6', '23'),('6', '24'),('6', '25'),('6', '26'),('6', '27'),('6', '28');
|
||||
CREATE TABLE hospitals (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
company_id INT UNSIGNED NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
code VARCHAR(3) NOT NULL,
|
||||
country VARCHAR(255) NOT NULL,
|
||||
region VARCHAR(255) NOT NULL,
|
||||
city VARCHAR(255) NOT NULL,
|
||||
address VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT hs_company_id
|
||||
FOREIGN KEY (company_id)
|
||||
REFERENCES companies(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX hs_company_id_idx (company_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE rooms (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
hospital_id INT UNSIGNED NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
CONSTRAINT ch_hospital_id
|
||||
FOREIGN KEY (hospital_id)
|
||||
REFERENCES hospitals(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE hospital_doctors (
|
||||
hospital_id INT UNSIGNED NOT NULL,
|
||||
doctor_id INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (hospital_id, doctor_id),
|
||||
CONSTRAINT hd_hospital_id
|
||||
FOREIGN KEY (hospital_id)
|
||||
REFERENCES hospitals(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX hd_hospital_id_idx (hospital_id),
|
||||
CONSTRAINT hd_doctor_id
|
||||
FOREIGN KEY (doctor_id)
|
||||
REFERENCES doctors(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX hd_doctor_id_idx (doctor_id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE appointments (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
patient_id INT UNSIGNED NOT NULL,
|
||||
doctor_id INT UNSIGNED NOT NULL,
|
||||
service_id INT UNSIGNED NOT NULL,
|
||||
hospital_id INT UNSIGNED DEFAULT NULL,
|
||||
room_id INT UNSIGNED DEFAULT NULL,
|
||||
date DATE NOT NULL,
|
||||
time TIME NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
CONSTRAINT ap_patient_id
|
||||
FOREIGN KEY (patient_id)
|
||||
REFERENCES patients(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ap_patient_id_idx (patient_id),
|
||||
CONSTRAINT ap_doctor_id
|
||||
FOREIGN KEY (doctor_id)
|
||||
REFERENCES doctors(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ap_doctor_id_idx (doctor_id),
|
||||
CONSTRAINT ap_service_id
|
||||
FOREIGN KEY (service_id)
|
||||
REFERENCES services(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ap_service_id_idx (service_id),
|
||||
CONSTRAINT ap_hospital_id
|
||||
FOREIGN KEY (hospital_id)
|
||||
REFERENCES hospitals(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ap_hospital_id_idx (hospital_id),
|
||||
CONSTRAINT ap_room_id
|
||||
FOREIGN KEY (room_id)
|
||||
REFERENCES rooms(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE,
|
||||
INDEX ap_room_id_idx (room_id)
|
||||
) ENGINE=InnoDB;
|
||||
28
index.js
28
index.js
@@ -5,17 +5,19 @@ import logger from 'morgan';
|
||||
import express from 'express';
|
||||
import cookieParser from 'cookie-parser';
|
||||
|
||||
import { log } from './modules/log';
|
||||
import { log } from './modules/logManager';
|
||||
import { speedLimiter, checkSystemLoad } from './modules/requestHandler';
|
||||
|
||||
import testRouter from './routes/test';
|
||||
import usersRouter from './routes/users';
|
||||
import pilotsRouter from './routes/pilots';
|
||||
import airplanesRouter from './routes/airplanes';
|
||||
import airlinesRouter from './routes/airlines';
|
||||
import airportsRouter from './routes/airports';
|
||||
import flightsRouter from './routes/flights';
|
||||
import seatsRouter from './routes/seats';
|
||||
import doctorsRouter from './routes/doctors';
|
||||
import patientsRouter from './routes/patients';
|
||||
import companiesRouter from './routes/companies';
|
||||
import hospitalsRouter from './routes/hospitals';
|
||||
|
||||
// create logs directory if it doesn't exist
|
||||
const logsDir = path.join(import.meta.dir, 'logs');
|
||||
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir);
|
||||
|
||||
const app = express();
|
||||
app.set('trust proxy', 1);
|
||||
@@ -25,7 +27,7 @@ app.use(cookieParser());
|
||||
app.use(speedLimiter);
|
||||
app.use(checkSystemLoad);
|
||||
app.use(logger('dev'));
|
||||
app.use(logger('combined', { stream: fs.createWriteStream(path.join(__dirname, 'logs/access.log'), { flags: 'a' }) }));
|
||||
app.use(logger('combined', { stream: fs.createWriteStream(path.join(import.meta.dir, 'logs/access.log'), { flags: 'a' }) }));
|
||||
app.use(cors({
|
||||
origin: '*',
|
||||
}));
|
||||
@@ -35,12 +37,10 @@ app.use(express.static('public'));
|
||||
// routes
|
||||
app.use('/api/test', testRouter);
|
||||
app.use('/api/users', usersRouter);
|
||||
app.use('/api/pilots', pilotsRouter);
|
||||
app.use('/api/airplanes', airplanesRouter);
|
||||
app.use('/api/airlines', airlinesRouter);
|
||||
app.use('/api/airports', airportsRouter);
|
||||
app.use('/api/flights', flightsRouter);
|
||||
app.use('/api/seats', seatsRouter);
|
||||
app.use('/api/doctors', doctorsRouter);
|
||||
app.use('/api/patients', patientsRouter);
|
||||
app.use('/api/companies', companiesRouter);
|
||||
app.use('/api/hospitals', hospitalsRouter);
|
||||
|
||||
// run the API
|
||||
app.listen(process.env.PORT, async () => {
|
||||
|
||||
187
logs/access.log
187
logs/access.log
@@ -1,187 +0,0 @@
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:21:41 +0000] "OPTIONS /user/login HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:21:41 +0000] "POST /user/login HTTP/1.1" 200 261 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:21:41 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:21:41 +0000] "GET /user/profile HTTP/1.1" 401 27 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:22:00 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:22:00 +0000] "GET /user/profile HTTP/1.1" 200 180 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:22:55 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:22:55 +0000] "GET /user/profile HTTP/1.1" 404 29 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:23:05 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:23:06 +0000] "GET /user/profile HTTP/1.1" 401 27 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:23:39 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:23:39 +0000] "POST /user/register HTTP/1.1" 500 35 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:24:21 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:24:21 +0000] "POST /user/register HTTP/1.1" 200 37 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:24:41 +0000] "OPTIONS /user/login HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:24:41 +0000] "POST /user/login HTTP/1.1" 200 261 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:24:41 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:24:41 +0000] "GET /user/profile HTTP/1.1" 200 190 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:27:36 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:28:16 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:28:16 +0000] "GET /user/profile HTTP/1.1" 304 - "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:30:08 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:30:08 +0000] "POST /user/register HTTP/1.1" 200 37 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:30:18 +0000] "OPTIONS /user/login HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:30:18 +0000] "POST /user/login HTTP/1.1" 200 258 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:30:18 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:30:18 +0000] "GET /user/profile HTTP/1.1" 200 177 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:33:05 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:33:05 +0000] "POST /user/register HTTP/1.1" 200 37 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:34:37 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:34:38 +0000] "POST /user/register HTTP/1.1" 200 37 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:36:28 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:36:28 +0000] "POST /user/register HTTP/1.1" 401 29 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:39:25 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:39:25 +0000] "POST /user/register HTTP/1.1" 200 37 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:40:34 +0000] "OPTIONS /user/register HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:40:34 +0000] "POST /user/register HTTP/1.1" 200 37 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:40:44 +0000] "OPTIONS /user/login HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:40:44 +0000] "POST /user/login HTTP/1.1" 200 275 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:40:44 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:40:44 +0000] "GET /user/profile HTTP/1.1" 200 194 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:44:45 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:44:45 +0000] "GET /user/profile HTTP/1.1" 304 - "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:46:02 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:46:02 +0000] "GET /user/profile HTTP/1.1" 304 - "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:46:46 +0000] "OPTIONS /user/profile HTTP/1.1" 204 0 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [15/Feb/2023:20:46:47 +0000] "GET /user/profile HTTP/1.1" 304 - "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:11 +0000] "GET / HTTP/1.1" 404 139 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:23 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:35 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:35 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:35 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:35 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:35 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:36 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:36 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:36 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:36 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:36 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:37 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:37 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:37 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:37 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:38 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:38 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:39 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:39 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:39 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:40 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:41 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:41 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:41 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:41 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:41 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:41 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:42 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:43 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:43 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:43 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:43 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:43 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:44 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:45 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:45 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:45 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:45 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:45 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:45 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:46 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:46 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:46 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:46 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:46 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:46 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:47 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:47 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:47 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:47 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:47 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:47 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:48 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:48 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:48 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:48 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:48 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:48 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:49 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:49 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:49 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:49 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:49 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:06:49 +0000] "GET /users HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:07:53 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:44 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:44 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:45 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:45 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:45 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:46 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:46 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:46 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:46 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:46 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:47 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:47 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:47 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:47 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:47 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:48 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:48 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:48 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:48 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:49 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:08:49 +0000] "GET /users/register HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:09:04 +0000] "GET /users/login HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:09:07 +0000] "GET /users/loginn HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:09:11 +0000] "GET /users/login HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:11:15 +0000] "GET /users/login HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:12:03 +0000] "POST /users/login HTTP/1.1" 500 35 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:14:49 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:15:14 +0000] "GET /users/login HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:15:44 +0000] "GET /users/verify HTTP/1.1" 401 31 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:16:30 +0000] "GET /users/verify HTTP/1.1" 500 35 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:16:31 +0000] "GET /users/verify HTTP/1.1" 500 35 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:16:31 +0000] "GET /users/verify HTTP/1.1" 500 35 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:18:28 +0000] "GET /users/verify HTTP/1.1" 400 25 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:18:37 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:18:55 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:19:37 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:20:01 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:42 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:51 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:52 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:52 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:53 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:53 +0000] "POST /users/login HTTP/1.1" 429 54 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:54 +0000] "POST /users/login HTTP/1.1" 429 54 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:23:55 +0000] "POST /users/login HTTP/1.1" 429 54 "-" "Wget/1.21.3"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:25:02 +0000] "GET /users/verify HTTP/1.1" 400 25 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:26:29 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "curl/7.84.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:28:59 +0000] "GET /test HTTP/1.1" 200 45 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:29:30 +0000] "POST /test HTTP/1.1" 200 46 "-" "curl/7.84.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:30:08 +0000] "POST /test HTTP/1.1" 200 46 "-" "curl/7.84.0"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:31:49 +0000] "POST /test HTTP/1.1" 200 46 "-" "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:32:12 +0000] "POST /users/login HTTP/1.1" 400 41 "-" "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:32:54 +0000] "POST /users/login HTTP/1.1" 400 41 "-" "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:33:50 +0000] "POST /users/login HTTP/1.1" 400 25 "-" "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:34:25 +0000] "POST /users/login HTTP/1.1" 400 41 "-" "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
|
||||
::ffff:127.0.0.1 - - [12/Mar/2023:13:35:27 +0000] "POST /users/login HTTP/1.1" 400 41 "-" "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
|
||||
48
modules/cronManager.js
Normal file
48
modules/cronManager.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import cron from 'node-cron';
|
||||
|
||||
const daysOfWeek = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
|
||||
const hoursOfDay = [...Array(24).keys()].map(hour => hour.toString());
|
||||
const minutesOfHour = [...Array(60).keys()].map(minute => minute.toString());
|
||||
|
||||
function toCronExpression(str) {
|
||||
switch (str.toLowerCase()) {
|
||||
case 'everyfiveseconds': {
|
||||
return '*/5 * * * * *';
|
||||
}
|
||||
case 'everythirtyseconds': {
|
||||
return '*/30 * * * * *';
|
||||
}
|
||||
case 'everyminute': {
|
||||
return '* * * * *';
|
||||
}
|
||||
case 'everyfiveminutes': {
|
||||
return '*/5 * * * *';
|
||||
}
|
||||
case 'everyfifteenminutes': {
|
||||
return '*/15 * * * *';
|
||||
}
|
||||
case 'everythirtyminutes': {
|
||||
return '*/30 * * * *';
|
||||
}
|
||||
case 'everyday': {
|
||||
return '0 0 * * *';
|
||||
}
|
||||
case 'weekdays': {
|
||||
return '0 0 * * 1-5';
|
||||
}
|
||||
case 'weekends': {
|
||||
return '0 0 * * 6,7';
|
||||
}
|
||||
default: {
|
||||
const [day, hour, minute] = str.toLowerCase().split(' ');
|
||||
const dayIndex = daysOfWeek.indexOf(day);
|
||||
const hourIndex = hoursOfDay.indexOf(hour);
|
||||
const minuteIndex = minutesOfHour.indexOf(minute);
|
||||
return `${minuteIndex} ${hourIndex} * * ${dayIndex}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createCron(rate, exec) {
|
||||
cron.schedule(toCronExpression(rate), exec);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import fetch from 'node-fetch';
|
||||
import { error } from './log';
|
||||
import { error } from './logManager';
|
||||
|
||||
async function get(url, token) {
|
||||
async function get(url, token = 'none') {
|
||||
const options = {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json', authorization: `${token}` },
|
||||
@@ -15,7 +15,7 @@ async function get(url, token) {
|
||||
.catch(err => error(err));
|
||||
}
|
||||
|
||||
async function post(url, body, token) {
|
||||
async function post(url, body, token = 'none') {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
@@ -31,7 +31,7 @@ async function post(url, body, token) {
|
||||
.catch(err => error(err));
|
||||
}
|
||||
|
||||
async function patch(url, body, token) {
|
||||
async function patch(url, body, token = 'none') {
|
||||
const options = {
|
||||
method: 'PATCH',
|
||||
mode: 'cors',
|
||||
@@ -47,7 +47,7 @@ async function patch(url, body, token) {
|
||||
.catch(err => error(err));
|
||||
}
|
||||
|
||||
async function put(url, body, token) {
|
||||
async function put(url, body, token = 'none') {
|
||||
const options = {
|
||||
method: 'PUT',
|
||||
mode: 'cors',
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'fs';
|
||||
import download from 'download';
|
||||
import random from './random';
|
||||
import { Readable } from 'stream';
|
||||
import { finished } from 'stream/promises';
|
||||
import { random } from './random';
|
||||
|
||||
function fileExist(path) {
|
||||
try {
|
||||
@@ -22,9 +23,11 @@ function fileDelete(path) {
|
||||
}
|
||||
}
|
||||
|
||||
function fileDownload(url, name) {
|
||||
async function fileDownload(url, path) {
|
||||
try {
|
||||
download(url, '../cdn/images/', { filename: name });
|
||||
const stream = fs.createWriteStream(path);
|
||||
const { body } = await fetch(url);
|
||||
await finished(Readable.fromWeb(body).pipe(stream));
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
@@ -32,6 +35,7 @@ function fileDownload(url, name) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function folderExist(path) {
|
||||
try {
|
||||
if (fs.existsSync(path)) {
|
||||
@@ -58,7 +62,7 @@ function getFilesFromFolder(path) {
|
||||
function randomFileFromFolder(path) {
|
||||
try {
|
||||
if (getFilesFromFolder(path)) {
|
||||
return random.random(0, getFilesFromFolder(path).length);
|
||||
return random(0, getFilesFromFolder(path).length);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
||||
@@ -22,4 +22,9 @@ export function isValidEmail(email) {
|
||||
|
||||
export function isNumber(x) {
|
||||
return /^-?[\d.]+(?:e-?\d+)?$/.test(x);
|
||||
}
|
||||
|
||||
export function isPhoneNumber(phone) {
|
||||
const phoneRegex = /^\d{10}$/;
|
||||
return phoneRegex.test(phone);
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
/* eslint-disable no-undef */
|
||||
import nodemailer from 'nodemailer';
|
||||
import { random } from './random';
|
||||
import { createPool } from './database';
|
||||
|
||||
const pool = createPool('localhost', 'root', '', 'postfixadmin');
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP,
|
||||
@@ -15,29 +12,6 @@ const transporter = nodemailer.createTransport({
|
||||
},
|
||||
});
|
||||
|
||||
async function createAddress(username, domain, password, name = '', backup_email = '', phone = '') {
|
||||
try {
|
||||
const hashedPassword = await Bun.password.hash(password, {
|
||||
type: Bun.password.argon2i,
|
||||
memoryCost: 2 ** 15,
|
||||
hashLength: 32,
|
||||
timeCost: 5,
|
||||
});
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `created`, `modified`, `active`, `phone`, `email_other`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[ username, hashedPassword, name, `${domain}/${username}`, 0, username, domain, Date.now(), Date.now(), '1', phone, backup_email],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function sendMail(email, head, body) {
|
||||
try {
|
||||
// setup email data
|
||||
@@ -63,30 +37,29 @@ function sendMail(email, head, body) {
|
||||
}
|
||||
}
|
||||
|
||||
function sendVerification(email, userId) {
|
||||
function sendVerification(email, userId, type = 'register', code = null) {
|
||||
try {
|
||||
const code = random(100000, 999999);
|
||||
if (sendMail(email, 'Your verification code for AirJet', `Verification code: ${code}\nLink: https://aostia.me/api/users/verify?u=${userId}&c=${code}`)) {
|
||||
return code;
|
||||
}
|
||||
else {
|
||||
code ? code : random(100000, 999999);
|
||||
let title, body;
|
||||
switch (type) {
|
||||
case 'email':
|
||||
title = 'Your verification code for HSP-GDH';
|
||||
body = `Verification code: ${code}\nLink: ${process.env.DOMAIN}/email/verify?code=${code}`;
|
||||
break;
|
||||
case 'password':
|
||||
title = 'Your password reset code for HSP-GDH';
|
||||
body = `Verification code: ${code}\nLink: ${process.env.DOMAIN}/password/reset?u=${userId}&c=${code}`;
|
||||
break;
|
||||
case '2fa':
|
||||
title = 'Your 2FA code for HSP-GDH';
|
||||
body = `Verification code: ${code}`;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
if (sendMail(email, title, body)) return code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function sendResetVerification(email, code = random(100000, 999999)) {
|
||||
try {
|
||||
if (sendMail(email, 'Your reset verification code for AirJet', `Verification code: ${code}`)) {
|
||||
return code;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return false;
|
||||
}
|
||||
@@ -95,6 +68,4 @@ function sendResetVerification(email, code = random(100000, 999999)) {
|
||||
export {
|
||||
sendMail,
|
||||
sendVerification,
|
||||
sendResetVerification,
|
||||
createAddress,
|
||||
};
|
||||
@@ -1,101 +0,0 @@
|
||||
import { pool } from '../modules/database.js';
|
||||
import { respondWithStatus } from './requestHandler.js';
|
||||
|
||||
// Middleware to verify the user permissions
|
||||
async function verifyPermissions(userId, perms_req) {
|
||||
|
||||
try {
|
||||
// Query the database to get the user
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (user.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query the database to get the perms and verify
|
||||
const [hasPerm] = await pool.execute(
|
||||
'SELECT COUNT(*) AS count FROM user_type_permissions WHERE user_type_id = ? AND permission_id = (SELECT id FROM permissions WHERE name = ?) LIMIT 1',
|
||||
[ user[0].user_type_id, perms_req ],
|
||||
);
|
||||
if (hasPerm.length === 0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const hasPermission = (perms_req) => async (req, res, next) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
|
||||
// Query the database to get the user
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (user.length === 0) {
|
||||
return await respondWithStatus(res, 401, 'User is invalid');
|
||||
}
|
||||
// Query the database to get the perms and verify
|
||||
const [hasPerm] = await pool.execute(
|
||||
'SELECT COUNT(*) AS count FROM user_type_permissions WHERE user_type_id = ? AND permission_id = (SELECT id FROM permissions WHERE name = ?) LIMIT 1',
|
||||
[ user[0].user_type_id, perms_req ],
|
||||
);
|
||||
if (req.originalUrl == '/api/users/me') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
if (hasPerm.length === 0) {
|
||||
return await respondWithStatus(res, 403, 'Missing permission');
|
||||
}
|
||||
else if (hasPerm[0].count == 0) {
|
||||
return await respondWithStatus(res, 403, 'Missing permission');
|
||||
}
|
||||
else {next();}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
};
|
||||
|
||||
async function checkBanned(req, res, next) {
|
||||
const userId = req.userId;
|
||||
try {
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (user.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
}
|
||||
if (user[0].is_banned) {
|
||||
return await respondWithStatus(res, 403, 'User is banned');
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
|
||||
async function isBanned(userId) {
|
||||
try {
|
||||
// Query the database to get the user
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (user.length === 0) {
|
||||
return true;
|
||||
}
|
||||
else if (user[0].is_banned == 1) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export { verifyPermissions, hasPermission, checkBanned, isBanned };
|
||||
65
modules/permissionManager.js
Normal file
65
modules/permissionManager.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { pool } from './databaseManager.js';
|
||||
import { respondWithStatus } from './requestHandler.js';
|
||||
import { error } from './logManager.js';
|
||||
|
||||
|
||||
export async function userExists(userId) {
|
||||
try {
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (user.length === 0) return false;
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
error(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function isBanned(userId) {
|
||||
try {
|
||||
const [bannedUser] = await pool.execute('SELECT * FROM bans WHERE user_id = ? LIMIT 1', [userId]);
|
||||
if (bannedUser.length > 0) return true;
|
||||
return false;
|
||||
}
|
||||
catch (err) {
|
||||
error(err);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// permissionType is bitfield
|
||||
// 1 = read
|
||||
// 2 = write
|
||||
// 4 = delete
|
||||
export async function verifyPermissions(userId, permissionName, permissionType) {
|
||||
try {
|
||||
const [perms] = await pool.execute(`SELECT r.${permissionName}_bitfield AS permissionBitfield FROM users u INNER JOIN user_roles ur ON u.id = ur.user_id INNER JOIN roles r ON ur.role_id = r.id WHERE u.id = ?`, [userId]);
|
||||
for (const row of perms) {
|
||||
if (row.permissionBitfield & permissionType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
error(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkUserExists(req, res, next) {
|
||||
const userId = req.userId;
|
||||
if (!userExists(userId)) return await respondWithStatus(res, 404, 'User not found');
|
||||
next();
|
||||
}
|
||||
|
||||
export async function checkBanned(req, res, next) {
|
||||
const userId = req.userId;
|
||||
if (isBanned(userId)) return await respondWithStatus(res, 403, 'User is banned');
|
||||
next();
|
||||
}
|
||||
|
||||
export const checkPermissions = (permissionName, permissionType) => async (req, res, next) => {
|
||||
const userId = req.userId;
|
||||
if (!verifyPermissions(userId, permissionName, permissionType)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
next();
|
||||
};
|
||||
@@ -1,9 +1,22 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
export function random(x, y) {
|
||||
return crypto.randomInt(x, y);
|
||||
return crypto.randomInt(x, y + 1);
|
||||
}
|
||||
|
||||
export function random2(min, max) {
|
||||
const range = max - min + 1;
|
||||
const byteLength = Math.ceil(Math.log2(range) / 8);
|
||||
let randomValue;
|
||||
|
||||
do {
|
||||
const randomBytes = crypto.randomBytes(byteLength);
|
||||
randomValue = parseInt(randomBytes.toString('hex'), 16);
|
||||
} while (randomValue >= range);
|
||||
|
||||
return randomValue + min;
|
||||
}
|
||||
|
||||
export function randomHEX(x) {
|
||||
return crypto.randomBytes(x).toString('hex');
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import rateLimit from 'express-rate-limit';
|
||||
import slowDown from 'express-slow-down';
|
||||
import http from 'http';
|
||||
import os from 'os';
|
||||
import { log } from './logManager';
|
||||
|
||||
const requestLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
@@ -23,7 +24,7 @@ function checkSystemLoad(req, res, next) {
|
||||
const threshold = cores * 0.7;
|
||||
|
||||
if (load > threshold) {
|
||||
console.log('System load too high, please try again later');
|
||||
log('System load too high, please try again later');
|
||||
return res.status(503).send(http.STATUS_CODES[503]);
|
||||
}
|
||||
|
||||
|
||||
101
modules/token.js
101
modules/token.js
@@ -1,101 +0,0 @@
|
||||
/* eslint-disable no-undef */
|
||||
import jwt from 'jsonwebtoken';
|
||||
import levelup from 'levelup';
|
||||
import leveldown from 'leveldown';
|
||||
import { respondWithStatus } from './requestHandler';
|
||||
import { pool } from './database';
|
||||
|
||||
|
||||
// Set up LevelDB instance
|
||||
const db = levelup(leveldown('./tokensDB'));
|
||||
|
||||
// Generate a new JWT
|
||||
const generateToken = async (userId, password) => {
|
||||
const token = jwt.sign({ userId: userId, password: password }, process.env.JWT_SECRET, { expiresIn: '7d' });
|
||||
await db.put(token, 'valid');
|
||||
return token;
|
||||
};
|
||||
|
||||
// Middleware to verify the JWT and set req.userId
|
||||
const verifyToken = async (req, res, next) => {
|
||||
const token = req.headers.authorization;
|
||||
if (!token) {
|
||||
return await respondWithStatus(res, 401, 'No token provided');
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
req.userId = decoded.userId;
|
||||
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM users WHERE id = ? LIMIT 1',
|
||||
[req.userId],
|
||||
);
|
||||
if (!rows.length) {
|
||||
return await respondWithStatus(res, 404, 'User not found!');
|
||||
}
|
||||
const passwordMatch = await Bun.password.verify(decoded.password, rows[0].password);
|
||||
if (!passwordMatch) {
|
||||
return await respondWithStatus(res, 401, 'Token is invalid');
|
||||
}
|
||||
// Check if the token is close to expiring
|
||||
const now = Date.now().valueOf() / 1000;
|
||||
if (decoded.exp - now < 36000) {
|
||||
// Generate a new token if the old one is close to expiring
|
||||
const newToken = generateToken(req.userId, decoded.password);
|
||||
res.cookie('token', newToken, {
|
||||
expires: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'strict',
|
||||
});
|
||||
res.set('Authorization', newToken);
|
||||
}
|
||||
|
||||
// Check if the token has been revoked
|
||||
const tokenStatus = await db.get(token);
|
||||
if (tokenStatus != 'valid') {
|
||||
return await respondWithStatus(res, 401, 'Token has been revoked ');
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
return await respondWithStatus(res, 401, 'Invalid user');
|
||||
}
|
||||
};
|
||||
|
||||
// Function to revoke a token
|
||||
const revokeToken = (token) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.put(token, 'revoked', (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Function to revoke all tokens of a user
|
||||
const revokeUserTokens = (userId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const tokensToRevoke = [];
|
||||
db.createReadStream()
|
||||
.on('data', (data) => {
|
||||
const token = data.key;
|
||||
const decoded = jwt.decode(token);
|
||||
if (decoded.userId === userId) {
|
||||
tokensToRevoke.push(token);
|
||||
}
|
||||
})
|
||||
.on('end', () => {
|
||||
Promise.all(tokensToRevoke.map(revokeToken))
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export { generateToken, verifyToken, revokeToken, revokeUserTokens };
|
||||
40
modules/tokenManager.js
Normal file
40
modules/tokenManager.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/* eslint-disable no-undef */
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Level } from 'level';
|
||||
import { respondWithStatus } from './requestHandler';
|
||||
import { userExists } from './permissionManager';
|
||||
|
||||
const db = new Level('tokens', { valueEncoding: 'json' });
|
||||
|
||||
export async function generateToken(userId, password) {
|
||||
const token = jwt.sign({ userId: userId, password: password }, process.env.JWT_SECRET, { expiresIn: '7d' });
|
||||
await db.put(token, 'valid');
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
export async function verifyToken(req, res, next) {
|
||||
const token = req.headers.authorization;
|
||||
if (!token) return await respondWithStatus(res, 401, 'No token provided');
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
req.userId = decoded.userId;
|
||||
|
||||
if (!userExists(userId)) return await respondWithStatus(res, 404, 'User not found');
|
||||
const passwordMatch = await Bun.password.verify(decoded.password, rows[0].password);
|
||||
if (!passwordMatch) return await respondWithStatus(res, 401, 'Token is invalid');
|
||||
const tokenStatus = await db.get(token);
|
||||
if (tokenStatus != 'valid') {
|
||||
return await respondWithStatus(res, 401, 'Token has been revoked ');
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
return await respondWithStatus(res, 401, 'Invalid user');
|
||||
}
|
||||
}
|
||||
|
||||
export async function revokeToken(token) {
|
||||
db.put(token, 'revoked');
|
||||
}
|
||||
12
package.json
12
package.json
@@ -3,6 +3,11 @@
|
||||
"module": "index.js",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/cookie-parser": "^1.4.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"bun-types": "latest",
|
||||
"eslint": "^8.54.0"
|
||||
},
|
||||
@@ -16,12 +21,11 @@
|
||||
"express-rate-limit": "^7.1.4",
|
||||
"express-slow-down": "^2.0.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"level": "^8.0.0",
|
||||
"leveldown": "^6.1.1",
|
||||
"levelup": "^5.1.1",
|
||||
"level": "^8.0.1",
|
||||
"morgan": "^1.10.0",
|
||||
"mysql2": "^3.6.4",
|
||||
"nodemailer": "^6.9.7",
|
||||
"node-cron": "^3.0.3",
|
||||
"nodemailer": "^6.9.10",
|
||||
"path": "^0.12.7",
|
||||
"pino": "^8.16.2"
|
||||
}
|
||||
|
||||
@@ -29,14 +29,13 @@
|
||||
<div class="container center">
|
||||
<div class="logo">
|
||||
<img src="./images/logo.png" alt="Logo">
|
||||
<h3>AOSTIA Jet</h3>
|
||||
<h3>HSP-GDH</h3>
|
||||
</div>
|
||||
|
||||
<div class="links">
|
||||
<ul>
|
||||
<li><a href="https://mail.aostia.com/">AOSTIA Mail</a></li>
|
||||
<li><a href="https://cloud.aostia.net/">AOSTIA Cloud</a></li>
|
||||
<li><a href="https://aostia.me/">AOSTIA Jet</a></li>
|
||||
<li><a href="https://mail.aostia.com/">Mail</a></li>
|
||||
<li><a href="https://cloud.aostia.net/">Cloud</a></li>
|
||||
<li><a id="toggleSignUp" class="btn toggleRegisterBtn">Sign up</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -53,10 +52,15 @@
|
||||
<div class="container">
|
||||
<div class="home">
|
||||
<div class="big-title">
|
||||
<h1>Fly with us,</h1>
|
||||
<h1>the sky's the limit!</h1>
|
||||
<h1>Stayin' Alive!</h1>
|
||||
</div>
|
||||
<p class="text">Fly with ease and control your journey with our airline's innovative flight management software. Whether you're booking your flights or making changes to your itinerary, our platform provides you with the flexibility and convenience you need to manage your flights with confidence.</p>
|
||||
<p class="text">Whether you're a brother or whether you're a mother<br>
|
||||
You're stayin' alive, stayin' alive<br>
|
||||
Feel the city breakin' and everybody shakin'<br>
|
||||
And we're stayin' alive, stayin' alive<br>
|
||||
Ah, ha, ha, ha, stayin' alive, stayin' alive<br>
|
||||
Ah, ha, ha, ha, stayin' alive<br>
|
||||
Oh when you walk</p>
|
||||
<div class="cta">
|
||||
<a id="toggleGetStarted" class="btn toggleLoginBtn">Get started</a>
|
||||
</div>
|
||||
@@ -95,24 +99,24 @@
|
||||
<h1>Register</h1>
|
||||
</div>
|
||||
<div id="register-form1" class="form-group">
|
||||
<label class="form-label text" for="registerUsername">Username:</label>
|
||||
<label class="form-label text" for="registerUsername">Username<span style="color: red;">*</span>:</label>
|
||||
<input class="form-input" type="text" id="registerUsername" name="username" required>
|
||||
|
||||
<label class="form-label text" for="registerEmail">Email:</label>
|
||||
<label class="form-label text" for="registerEmail">Email<span style="color: red;">*</span>:</label>
|
||||
<input class="form-input" type="email" id="registerEmail" name="email" required>
|
||||
|
||||
<label class="form-label text" for="registerPassword">Password:</label>
|
||||
<label class="form-label text" for="registerPassword">Password<span style="color: red;">*</span>:</label>
|
||||
<input class="form-input" type="password" id="registerPassword" name="password" required>
|
||||
</div>
|
||||
<div id="register-form2" class="form-group hidden">
|
||||
<label class="form-label text" for="registerName">First name:</label>
|
||||
<label class="form-label text" for="registerName">First name<span style="color: red;">*</span>:</label>
|
||||
<input class="form-input" type="text" id="registerName" name="name" required>
|
||||
|
||||
<label class="form-label text" for="registerLastname">Last name:</label>
|
||||
<label class="form-label text" for="registerLastname">Last name<span style="color: red;">*</span>:</label>
|
||||
<input class="form-input" type="text" id="registerLastname" name="lastname" required>
|
||||
|
||||
<label class="form-label text" for="registerPhone">Phone:</label>
|
||||
<input class="form-input" type="tel" id="registerPhone" name="phone" pattern="[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}">
|
||||
<input class="form-input" type="tel" id="registerPhone" name="phone" pattern="[0-9]{2} [0-9]{2} [0-9]{2} [0-9]{2} [0-9]{2}">
|
||||
</div>
|
||||
<button id="register-next" class="form-button registerNextBtn" type="button">Next</button>
|
||||
<div id="register-btn-2" class="hidden">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const api = 'https://aostia.me/api';
|
||||
/* eslint-disable no-undef */
|
||||
const api = window.location.origin + '/api';
|
||||
const loginForm = document.getElementById('loginForm');
|
||||
const registerForm = document.getElementById('registerForm');
|
||||
const resetPasswordForm = document.getElementById('resetPasswordForm');
|
||||
@@ -11,7 +12,7 @@ const register = document.getElementById('register');
|
||||
const forgot = document.getElementById('forgotPassword');
|
||||
|
||||
function events() {
|
||||
document.querySelector('.toggleThemeBtn').addEventListener('click', toggleTheme);
|
||||
document.querySelector('.toggleThemeBtn').addEventListener('click', toggleTheme);
|
||||
document.querySelectorAll('.toggleForgotPasswordBtn').forEach(button => button.addEventListener('click', () => togglePage('forgotPassword')));
|
||||
document.querySelectorAll('.toggleRegisterBtn').forEach(button => button.addEventListener('click', () => togglePage('register')));
|
||||
document.querySelectorAll('.toggleLoginBtn').forEach(button => button.addEventListener('click', () => togglePage('login')));
|
||||
@@ -84,7 +85,7 @@ function dbox(msg) {
|
||||
window.onload = (event) => {
|
||||
events();
|
||||
togglePage(localStorage.getItem('page') || 'home');
|
||||
loginForm.addEventListener('submit', async (event) => {
|
||||
loginForm.addEventListener('submit', async () => {
|
||||
event.preventDefault();
|
||||
const { status, data } = await post(`${api}/users/login`, { usernameOrEmail: loginForm.elements['usernameOrEmail'].value, password: loginForm.elements['password'].value });
|
||||
|
||||
@@ -101,7 +102,7 @@ window.onload = (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
registerForm.addEventListener('submit', async (event) => {
|
||||
registerForm.addEventListener('submit', async () => {
|
||||
event.preventDefault();
|
||||
|
||||
const username = registerForm.elements['username'].value;
|
||||
@@ -114,7 +115,6 @@ window.onload = (event) => {
|
||||
const { status, data } = await post(`${api}/users/register`, { username: username, email: email, password: password, first_name: first_name, last_name: last_name, phone: phone });
|
||||
|
||||
if (status != 200) {
|
||||
const data = await response.json();
|
||||
dbox(`${data.message}`);
|
||||
console.error(data);
|
||||
}
|
||||
@@ -125,7 +125,7 @@ window.onload = (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
requestResetPasswordForm.addEventListener('submit', async (event) => {
|
||||
requestResetPasswordForm.addEventListener('submit', async () => {
|
||||
event.preventDefault();
|
||||
const { status, data } = await post(`${api}/users/changepassword`, { usernameOrEmail: requestResetPasswordForm.elements['usernameOrEmail'].value });
|
||||
|
||||
@@ -140,7 +140,7 @@ window.onload = (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
verifyResetPasswordForm.addEventListener('submit', async (event) => {
|
||||
verifyResetPasswordForm.addEventListener('submit', async () => {
|
||||
event.preventDefault();
|
||||
const { status, data } = await get(`${api}/users/verify?c=${verifyResetPasswordForm.elements['code'].value}&u=${requestResetPasswordForm.elements['usernameOrEmail'].value}`);
|
||||
if (status != 200) {
|
||||
@@ -153,8 +153,8 @@ window.onload = (event) => {
|
||||
verifyResetPasswordForm.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
resetPasswordForm.addEventListener('submit', async (event) => {
|
||||
|
||||
resetPasswordForm.addEventListener('submit', async () => {
|
||||
event.preventDefault();
|
||||
const { status, data } = await patch(`${api}/users/changepassword`, { code: verifyResetPasswordForm.elements['code'].value, usernameOrEmail: requestResetPasswordForm.elements['usernameOrEmail'].value, password: resetPasswordForm.elements['password'].value });
|
||||
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { verifyToken } from '../modules/token';
|
||||
import { hasPermission, checkBanned } from '../modules/permission';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_airlines'), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM airlines WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airlines not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_airlines'), async (req, res) => {
|
||||
const { name, code, logo } = req.body;
|
||||
if ([ name, code, logo ].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO airlines (name, code, logo) VALUES (?, ?, ?)',
|
||||
[ name, code, logo ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing airline');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airline created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:airlineId', verifyToken, checkBanned, hasPermission('view_airlines'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airlineId;
|
||||
const [rows] = await pool.execute('SELECT * FROM airlines WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airline not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:airlineId', verifyToken, checkBanned, hasPermission('edit_airlines'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airlineId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM airlines WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airline not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE airlines SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating airline');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airline updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:airlineId', verifyToken, checkBanned, hasPermission('edit_airlines'), async (req, res) => {
|
||||
const id = req.params.airlineId;
|
||||
const { name, code, logo } = req.body;
|
||||
if ([name, code, logo].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM airlines WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airline not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE airlines SET name = ?, code = ?, logo = ? WHERE id = ?',
|
||||
[name, code, logo, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating airline');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airline updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:airlineId', verifyToken, checkBanned, hasPermission('delete_airlines'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airlineId;
|
||||
const [rows] = await pool.execute('SELECT * FROM airlines WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airline not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM airlines WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing airline');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airline removed successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1,143 +0,0 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { verifyToken } from '../modules/token';
|
||||
import { hasPermission, checkBanned } from '../modules/permission';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_airplanes'), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM airplanes WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airplanes not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_airplanes'), async (req, res) => {
|
||||
const { name, type, manufacturer, capacity, status, location } = req.body;
|
||||
if ([name, type, manufacturer, capacity, status, location].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO airplanes (name, type, manufacturer, capacity, status, location) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ name, type, manufacturer, capacity, status, location ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing airplane');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airplane created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:airplaneId', verifyToken, checkBanned, hasPermission('view_airplanes'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airplaneId;
|
||||
const [rows] = await pool.execute('SELECT * FROM airplanes WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airplane not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:airplaneId', verifyToken, checkBanned, hasPermission('edit_airplanes'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airplaneId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM airplanes WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airplane not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE airplanes SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating airplane');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airplane updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:airplaneId', verifyToken, checkBanned, hasPermission('edit_airplanes'), async (req, res) => {
|
||||
const id = req.params.airplaneId;
|
||||
const { name, type, manufacturer, capacity, status, location } = req.body;
|
||||
if ([name, type, manufacturer, capacity, status, location].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM airplanes WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airplane not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE airplanes SET name = ?, type = ?, manufacturer = ?, capacity = ?, status = ?, location = ? WHERE id = ?',
|
||||
[name, type, manufacturer, capacity, status, location, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating airplane');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airplane updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:airplaneId', verifyToken, checkBanned, hasPermission('delete_airplanes'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airplaneId;
|
||||
const [rows] = await pool.execute('SELECT * FROM airplanes WHERE id = ? LIMIT', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airplane not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM airplanes WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing airplane');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airplane deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1,143 +0,0 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { verifyToken } from '../modules/token';
|
||||
import { hasPermission, checkBanned } from '../modules/permission';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_airports'), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM airports WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airports not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_airports'), async (req, res) => {
|
||||
const { name, code, city, country, latitude, longitude } = req.body;
|
||||
if ([name, code, city, country, latitude, longitude].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO airports (name, code, city, country, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ name, code, city, country, latitude, longitude ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing airport');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airport created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:airportId', verifyToken, checkBanned, hasPermission('view_airports'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airportId;
|
||||
const [rows] = await pool.execute('SELECT * FROM airports WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airports not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:airportId', verifyToken, checkBanned, hasPermission('edit_airports'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airportId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM airports WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airport not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE airports SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating airport');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airport updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:airportId', verifyToken, checkBanned, hasPermission('edit_airports'), async (req, res) => {
|
||||
const id = req.params.airportId;
|
||||
const { name, code, city, country, latitude, longitude } = req.body;
|
||||
if ([name, code, city, country, latitude, longitude].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM airports WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airport not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE airports SET name = ?, code = ?, city = ?, country = ?, latitude = ?, longitude = ? WHERE id = ?',
|
||||
[name, code, city, country, latitude, longitude, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating airport');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airport updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:airportId', verifyToken, checkBanned, hasPermission('delete_airports'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.airportId;
|
||||
const [rows] = await pool.execute('SELECT * FROM airports WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Airport not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM airports WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing airport');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Airport deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
128
routes/companies.js
Normal file
128
routes/companies.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/databaseManager';
|
||||
import { verifyToken } from '../modules/tokenManager';
|
||||
import { checkPermissions, checkBanned } from '../modules/permissionManager';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, checkPermissions('companies', 1), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM companies WHERE 1');
|
||||
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Companies not found');
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, checkPermissions('companies', 2), async (req, res) => {
|
||||
const { name, code, logo } = req.body;
|
||||
if ([ name, code, logo ].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO companies (name, code, logo) VALUES (?, ?, ?)',
|
||||
[ name, code, logo ],
|
||||
);
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error storing companie');
|
||||
return await respondWithStatus(res, 200, 'Company created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:companyId', verifyToken, checkBanned, checkPermissions('companies', 1), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.companyId;
|
||||
const [rows] = await pool.execute('SELECT * FROM companies WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Company not found');
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:companyId', verifyToken, checkBanned, checkPermissions('companies', 2), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.companyId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM companies WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Company not found');
|
||||
|
||||
const excludedKeys = ['id'];
|
||||
const fields = rows.map(row => Object.keys(row).filter(key => !excludedKeys.includes(key)));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE companies SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating companie');
|
||||
return await respondWithStatus(res, 200, 'Company updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:companyId', verifyToken, checkBanned, checkPermissions('companies', 2), async (req, res) => {
|
||||
const id = req.params.companyId;
|
||||
const { name, code, logo } = req.body;
|
||||
if ([name, code, logo].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM companies WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Company not found');
|
||||
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE companies SET name = ?, code = ?, logo = ? WHERE id = ?',
|
||||
[name, code, logo, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating companie');
|
||||
return await respondWithStatus(res, 200, 'Company updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:companyId', verifyToken, checkBanned, checkPermissions('companies', 4), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.companyId;
|
||||
const [rows] = await pool.execute('SELECT * FROM companies WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Company not found');
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM companies WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error removing companie');
|
||||
return await respondWithStatus(res, 200, 'Company removed successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
// Hospital endpoints
|
||||
// GET /:companyId/hospitals
|
||||
|
||||
|
||||
export default router;
|
||||
151
routes/doctors.js
Normal file
151
routes/doctors.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/databaseManager';
|
||||
import { verifyToken } from '../modules/tokenManager';
|
||||
import { verifyPermissions, checkPermissions, checkBanned } from '../modules/permissionManager';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* Retrieves all doctors from the database.
|
||||
*
|
||||
* @returns {Promise<Array>} A promise that resolves to an array of doctor objects.
|
||||
*/
|
||||
router.get('/', verifyToken, checkBanned, checkPermissions('doctors', 1), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM doctors WHERE 1');
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Doctors not found');
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Inserts a new doctor record into the database.
|
||||
*
|
||||
* @param {number} user_id - The ID of the user associated with the doctor.
|
||||
* @param {date} date_of_birth - The date of birth of the doctor.
|
||||
* @param {string} gender - The gender of the doctor.
|
||||
* @param {string} address - The address of the doctor.
|
||||
* @param {string} social_security_number - The social security number of the doctor.
|
||||
* @param {string} insurance_number - The insurance number of the doctor.
|
||||
* @returns {Promise} - A promise that resolves with the result of the insertion.
|
||||
*/
|
||||
router.post('/', verifyToken, checkBanned, checkPermissions('doctors', 2), async (req, res) => {
|
||||
const { user_id, date_of_birth, gender, address, social_security_number, insurance_number } = req.body;
|
||||
if ([ user_id, date_of_birth, gender, address, social_security_number, insurance_number ].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO doctors (user_id, date_of_birth, gender, address, social_security_number, insurance_number) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ user_id, date_of_birth, gender, address, social_security_number, insurance_number ],
|
||||
);
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error storing doctor');
|
||||
return await respondWithStatus(res, 200, 'Doctor created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:doctorId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const id = req.params.doctorId;
|
||||
const [rows] = await pool.execute('SELECT * FROM doctors WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Doctor not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'doctors', 1)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:doctorId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const id = req.params.doctorId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM doctors WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Doctor not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'doctors', 2)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
|
||||
const excludedKeys = [ 'id', 'user_id' ];
|
||||
const fields = rows.map(row => Object.keys(row).filter(key => !excludedKeys.includes(key)));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE doctors SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating doctor');
|
||||
return await respondWithStatus(res, 200, 'Doctor updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:doctorId', verifyToken, checkBanned, async (req, res) => {
|
||||
const id = req.params.doctorId;
|
||||
const { user_id, date_of_birth, gender, address, social_security_number, insurance_number } = req.body;
|
||||
if ([ user_id, date_of_birth, gender, address, social_security_number, insurance_number ].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM doctors WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Doctor not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'doctors', 2)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE doctors SET name = ?, type = ?, manufacturer = ?, capacity = ?, status = ?, location = ? WHERE id = ?',
|
||||
[user_id, date_of_birth, gender, address, social_security_number, insurance_number, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating doctor');
|
||||
return await respondWithStatus(res, 200, 'Doctor updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:doctorId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const id = req.params.doctorId;
|
||||
const [rows] = await pool.execute('SELECT * FROM doctors WHERE id = ? LIMIT', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Doctor not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'doctors', 4)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM doctors WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error removing doctor');
|
||||
return await respondWithStatus(res, 200, 'Doctor deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
// Appointments endpoints
|
||||
// GET /:doctorId/appointments
|
||||
// POST /:doctorId/appointments
|
||||
// GET /:doctorId/appointments/:appointmentId
|
||||
// PATCH /:doctorId/appointments/:appointmentId
|
||||
// PUT /:doctorId/appointments/:appointmentId
|
||||
// DELETE /:doctorId/appointments/:appointmentId
|
||||
|
||||
export default router;
|
||||
@@ -1,143 +0,0 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { verifyToken } from '../modules/token';
|
||||
import { hasPermission, checkBanned } from '../modules/permission';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_flights'), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM flights');
|
||||
|
||||
if (!rows.length) {
|
||||
return await respondWithStatus(res, 404, 'Flights not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_flights'), async (req, res) => {
|
||||
const { airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status } = req.body;
|
||||
if ([airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO flights (airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[ airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing flight');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Flight created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:flightId', verifyToken, checkBanned, hasPermission('view_flights'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.flightId;
|
||||
const [rows] = await pool.execute('SELECT * FROM flights WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Flight not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:flightId', verifyToken, checkBanned, hasPermission('edit_flights'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.flightId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM flights WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Flight not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE flights SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating flight');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Flight updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:flightId', verifyToken, checkBanned, hasPermission('edit_flights'), async (req, res) => {
|
||||
const id = req.params.flightId;
|
||||
const { airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status } = req.body;
|
||||
if ([airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM flights WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Flight not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE flights SET airline_id = ?, pilot_id = ?, flight_no = ?, origin_id = ?, destination_id = ?, departure_time = ?, arrival_time = ?, duration_minutes= ?, price_economy = ?, price_business = ?, price_first_class = ?, status = ? WHERE id = ?',
|
||||
[airline_id, pilot_id, flight_no, origin_id, destination_id, departure_time, arrival_time, duration_minutes, price_economy, price_business, price_first_class, status, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating flight');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Flight updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:flightId', verifyToken, checkBanned, hasPermission('delete_flights'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.flightId;
|
||||
const [rows] = await pool.execute('SELECT * FROM flights WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Flight not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM flights WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing flight');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Flight deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
156
routes/hospitals.js
Normal file
156
routes/hospitals.js
Normal file
@@ -0,0 +1,156 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/databaseManager';
|
||||
import { verifyToken } from '../modules/tokenManager';
|
||||
import { checkPermissions, checkBanned } from '../modules/permissionManager';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, checkPermissions('hospitals', 1), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM hospitals WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Hospitals not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, checkPermissions('hospitals', 2), async (req, res) => {
|
||||
const { company_id, name, code, country, region, city, address } = req.body;
|
||||
if ([ company_id, name, code, country, region, city, address ].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO hospitals (company_id, name, code, country, region, city, address) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
[ company_id, name, code, country, region, city, address ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing hospital');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Hospital created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:hospitalId', verifyToken, checkBanned, checkPermissions('hospitals', 1), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.hospitalId;
|
||||
const [rows] = await pool.execute('SELECT * FROM hospitals WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Hospitals not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:hospitalId', verifyToken, checkBanned, checkPermissions('hospitals', 2), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.hospitalId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM hospitals WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Hospital not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE hospitals SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating hospital');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Hospital updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:hospitalId', verifyToken, checkBanned, checkPermissions('hospitals', 2), async (req, res) => {
|
||||
const id = req.params.hospitalId;
|
||||
const { company_id, name, code, country, region, city, address } = req.body;
|
||||
if ([company_id, name, code, country, region, city, address].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM hospitals WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Hospital not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE hospitals SET company_id = ?, name = ?, country = ?, region = ?, city = ?, address = ? WHERE id = ?',
|
||||
[company_id, name, code, country, region, city, address, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating hospital');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Hospital updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:hospitalId', verifyToken, checkBanned, checkPermissions('hospitals', 4), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.hospitalId;
|
||||
const [rows] = await pool.execute('SELECT * FROM hospitals WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Hospital not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM hospitals WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing hospital');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Hospital deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
// Doctor endpoints
|
||||
// GET all doctors in a hospital
|
||||
// POST a new doctor to a hospital
|
||||
// DELETE a doctor from a hospital
|
||||
|
||||
// Service endpoints
|
||||
// GET all services in a hospital
|
||||
|
||||
// Room endpoints
|
||||
// GET all rooms in a hospital
|
||||
// POST a new room to a hospital
|
||||
// DELETE a room from a hospital
|
||||
|
||||
export default router;
|
||||
151
routes/patients.js
Normal file
151
routes/patients.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/databaseManager';
|
||||
import { verifyToken } from '../modules/tokenManager';
|
||||
import { verifyPermissions, checkPermissions, checkBanned } from '../modules/permissionManager';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* Retrieves all patients from the database.
|
||||
*
|
||||
* @returns {Promise<Array>} A promise that resolves to an array of patient objects.
|
||||
*/
|
||||
router.get('/', verifyToken, checkBanned, checkPermissions('patients', 1), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM patients WHERE 1');
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Patients not found');
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Inserts a new patient record into the database.
|
||||
*
|
||||
* @param {number} user_id - The ID of the user associated with the patient.
|
||||
* @param {date} date_of_birth - The date of birth of the patient.
|
||||
* @param {string} gender - The gender of the patient.
|
||||
* @param {string} address - The address of the patient.
|
||||
* @param {string} social_security_number - The social security number of the patient.
|
||||
* @param {string} insurance_number - The insurance number of the patient.
|
||||
* @returns {Promise} - A promise that resolves with the result of the insertion.
|
||||
*/
|
||||
router.post('/', verifyToken, checkBanned, checkPermissions('patients', 2), async (req, res) => {
|
||||
const { user_id, date_of_birth, gender, address, social_security_number, insurance_number } = req.body;
|
||||
if ([ user_id, date_of_birth, gender, address, social_security_number, insurance_number ].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO patients (user_id, date_of_birth, gender, address, social_security_number, insurance_number) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ user_id, date_of_birth, gender, address, social_security_number, insurance_number ],
|
||||
);
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error storing patient');
|
||||
return await respondWithStatus(res, 200, 'Patient created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:patientId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const id = req.params.patientId;
|
||||
const [rows] = await pool.execute('SELECT * FROM patients WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Patient not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'patients', 1)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:patientId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const id = req.params.patientId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM patients WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Patient not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'patients', 2)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
|
||||
const excludedKeys = [ 'id', 'user_id' ];
|
||||
const fields = rows.map(row => Object.keys(row).filter(key => !excludedKeys.includes(key)));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE patients SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating patient');
|
||||
return await respondWithStatus(res, 200, 'Patient updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:patientId', verifyToken, checkBanned, async (req, res) => {
|
||||
const id = req.params.patientId;
|
||||
const { user_id, date_of_birth, gender, address, social_security_number, insurance_number } = req.body;
|
||||
if ([ user_id, date_of_birth, gender, address, social_security_number, insurance_number ].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM patients WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Patient not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'patients', 2)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE patients SET name = ?, type = ?, manufacturer = ?, capacity = ?, status = ?, location = ? WHERE id = ?',
|
||||
[user_id, date_of_birth, gender, address, social_security_number, insurance_number, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating patient');
|
||||
return await respondWithStatus(res, 200, 'Patient updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:patientId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const id = req.params.patientId;
|
||||
const [rows] = await pool.execute('SELECT * FROM patients WHERE id = ? LIMIT', [id]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Patient not found');
|
||||
if (rows[0].userId != req.userId && !verifyPermissions(req.userId, 'patients', 4)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM patients WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error removing patient');
|
||||
return await respondWithStatus(res, 200, 'Patient deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
// Appointments endpoints
|
||||
// GET /:patientId/appointments
|
||||
// POST /:patientId/appointments
|
||||
// GET /:patientId/appointments/:appointmentId
|
||||
// PATCH /:patientId/appointments/:appointmentId
|
||||
// PUT /:patientId/appointments/:appointmentId
|
||||
// DELETE /:patientId/appointments/:appointmentId
|
||||
|
||||
export default router;
|
||||
144
routes/pilots.js
144
routes/pilots.js
@@ -1,144 +0,0 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { verifyToken } from '../modules/token';
|
||||
import { hasPermission, checkBanned } from '../modules/permission';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_pilots'), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM pilots WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Pilots not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_pilots'), async (req, res) => {
|
||||
const { first_name, last_name, email, phone, license_number, license_expiry, salary, status } = req.body;
|
||||
if ([first_name, last_name, email, phone, license_number, license_expiry, salary, status].every(Boolean)) {
|
||||
try {
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO pilots (first_name, last_name, email, phone, license_number, license_expiry, salary, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[ first_name, last_name, email, phone, license_number, license_expiry, salary, status ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing pilot');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Pilot created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:pilotId', verifyToken, checkBanned, hasPermission('view_pilots'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.pilotId;
|
||||
const [rows] = await pool.execute('SELECT * FROM pilots WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Pilot not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:pilotId', verifyToken, checkBanned, hasPermission('edit_pilots'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.pilotId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM pilots WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Pilot not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE pilots SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating pilot');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Pilot updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:pilotId', verifyToken, checkBanned, hasPermission('edit_pilots'), async (req, res) => {
|
||||
const id = req.params.pilotId;
|
||||
const { first_name, last_name, email, phone, license_number, license_expiry, salary, status } = req.body;
|
||||
if ([first_name, last_name, email, phone, license_number, license_expiry, salary, status].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM pilots WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Pilot not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE pilots SET first_name = ?, last_name = ?, email = ?, phone = ?, license_number = ?, license_expiry = ?, salary = ?, status = ? WHERE id = ?',
|
||||
[first_name, last_name, email, phone, license_number, license_expiry, salary, status, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating pilot');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Pilot updated successfully');
|
||||
}
|
||||
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:pilotId', verifyToken, checkBanned, hasPermission('delete_pilots'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.pilotId;
|
||||
const [rows] = await pool.execute('SELECT * FROM pilots WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Pilot not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM pilots WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing pilot');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Pilot removed successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
155
routes/seats.js
155
routes/seats.js
@@ -1,155 +0,0 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { verifyToken } from '../modules/token';
|
||||
import { hasPermission, checkBanned } from '../modules/permission';
|
||||
import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_seats'), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM seats WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Seats not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_seats'), async (req, res) => {
|
||||
const { user_id, flight_id, place_no, seat_class } = req.body;
|
||||
if ([ user_id, flight_id, place_no, seat_class ].every(Boolean)) {
|
||||
try {
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [user_id]);
|
||||
|
||||
if (user.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
}
|
||||
|
||||
const [flight] = await pool.execute('SELECT * FROM flights WHERE id = ? LIMIT 1', [flight_id]);
|
||||
|
||||
if (flight.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Flight not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO seats (user_id, flight_id, place_no, class) VALUES (?, ?, ?, ?)',
|
||||
[ user_id, flight_id, place_no, seat_class ],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing seat');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Seat created successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:seatId', verifyToken, checkBanned, hasPermission('view_seats'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.seatId;
|
||||
const [rows] = await pool.execute('SELECT * FROM seats WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Seat not found');
|
||||
}
|
||||
return await respondWithStatusJSON(res, 200, rows[0]);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:seatId', verifyToken, checkBanned, hasPermission('edit_seats'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.seatId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM seats WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Seat not found');
|
||||
}
|
||||
const fields = rows.map(row => Object.keys(row));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE seats SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating seat');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Seat updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:seatId', verifyToken, checkBanned, hasPermission('edit_seats'), async (req, res) => {
|
||||
const id = req.params.seatId;
|
||||
const { user_id, flight_id, place_no, seat_class } = req.body;
|
||||
if ([ user_id, flight_id, place_no, seat_class ].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM seats WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Seat not found');
|
||||
}
|
||||
const [result] = await pool.execute(
|
||||
'UPDATE seats SET user_id = ?, flight_id = ?, place_no = ?, class = ? WHERE id = ?',
|
||||
[user_id, flight_id, place_no, seat_class, id],
|
||||
);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating seat');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Seat updated successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:seatId', verifyToken, checkBanned, hasPermission('delete_seats'), async (req, res) => {
|
||||
try {
|
||||
const id = req.params.seatId;
|
||||
const [rows] = await pool.execute('SELECT * FROM seats WHERE id = ? LIMIT 1', [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Seat not found');
|
||||
}
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM seats WHERE id = ?', [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing seat');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Seat removed successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
519
routes/users.js
519
routes/users.js
@@ -1,49 +1,46 @@
|
||||
import express from 'express';
|
||||
import { pool } from '../modules/database';
|
||||
import { sendVerification, sendResetVerification } from '../modules/mailHandler';
|
||||
import { isEmailDomainValid, isValidEmail, isNumber } from '../modules/formatHandler';
|
||||
import { hasPermission, checkBanned, isBanned } from '../modules/permission';
|
||||
import { verifyToken, generateToken, revokeUserTokens } from '../modules/token';
|
||||
import { error } from '../modules/logManager';
|
||||
import { pool } from '../modules/databaseManager';
|
||||
import { sendVerification } from '../modules/mailHandler';
|
||||
import { isEmailDomainValid, isValidEmail, isPhoneNumber } from '../modules/formatManager';
|
||||
import { checkBanned, checkPermissions, userExists, isBanned, verifyPermissions } from '../modules/permissionManager';
|
||||
import { verifyToken, generateToken } from '../modules/tokenManager';
|
||||
import { requestLimiter, respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/register', requestLimiter, async (req, res) => {
|
||||
const { username, email, password, first_name, last_name, phone = 'none' } = req.body;
|
||||
const { username, email, password, first_name, last_name, phone = null } = req.body;
|
||||
if ([ username, email, password, first_name, last_name ].every(Boolean)) {
|
||||
try {
|
||||
if (isValidEmail(email) && isEmailDomainValid(email)) {
|
||||
const [existingUsername] = await pool.execute('SELECT * FROM users WHERE username = ? LIMIT 1', [username]);
|
||||
if (existingUsername.length) {
|
||||
return await respondWithStatus(res, 400, 'Username is already taken');
|
||||
}
|
||||
if (existingUsername.length) return await respondWithStatus(res, 400, 'Username is already taken');
|
||||
|
||||
const [existingEmail] = await pool.execute('SELECT * FROM users WHERE email = ? LIMIT 1', [email]);
|
||||
if (existingEmail.length) {
|
||||
return await respondWithStatus(res, 400, 'Email is already taken');
|
||||
}
|
||||
if (existingEmail.length) return await respondWithStatus(res, 400, 'Email is already taken');
|
||||
|
||||
if (!isPhoneNumber(phone)) return await respondWithStatus(res, 400, 'Invalid phone number');
|
||||
|
||||
const hashedPassword = await Bun.password.hash(password);
|
||||
const [unverifiedId] = await pool.execute(
|
||||
'SELECT id FROM user_types WHERE name = \'unverified\' LIMIT 1',
|
||||
);
|
||||
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO users (first_name, last_name, username, email, password, user_type_id, phone) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
[ first_name, last_name, username, email, hashedPassword, unverifiedId[0].id, phone ],
|
||||
'INSERT INTO users (first_name, last_name, username, email, password, phone) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ first_name, last_name, username, email, hashedPassword, phone ? phone : 'None'],
|
||||
);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error storing user');
|
||||
}
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error storing user');
|
||||
|
||||
const [rows] = await pool.execute('SELECT id FROM users WHERE email = ? LIMIT 1', [email]);
|
||||
const code = sendVerification(email, rows[0].id);
|
||||
pool.execute('INSERT INTO user_email_verifications (user_id, verification_code, type) VALUES (?, ?, ?)', [ rows[0].id, code, 'register' ]);
|
||||
const code = sendVerification(email, rows[0].id, 'email');
|
||||
pool.execute('INSERT INTO verification_codes (user_id, verification_code, type) VALUES (?, ?, ?)', [ rows[0].id, code, 'email' ]);
|
||||
return await respondWithStatus(res, 200, 'Successfully registered');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid email address');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
catch (err) {
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
@@ -60,39 +57,28 @@ router.post('/login', requestLimiter, async (req, res) => {
|
||||
'SELECT * FROM users WHERE username = ? OR email = ? LIMIT 1',
|
||||
[usernameOrEmail, usernameOrEmail],
|
||||
);
|
||||
if (!rows.length) {
|
||||
return await respondWithStatus(res, 404, 'Incorrect username or email');
|
||||
}
|
||||
if (!rows.length) return await respondWithStatus(res, 404, 'Incorrect username or email');
|
||||
|
||||
const user = rows[0];
|
||||
const passwordMatch = await Bun.password.verify(password, user.password);
|
||||
if (!passwordMatch) {
|
||||
return await respondWithStatus(res, 401, 'Incorrect password');
|
||||
}
|
||||
if (isBanned(user.id)) {
|
||||
const token = await generateToken(user.id, password);
|
||||
res.cookie('token', token, {
|
||||
expires: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'strict',
|
||||
});
|
||||
return await respondWithStatusJSON(res, 200, {
|
||||
message: 'Login successful',
|
||||
token: token,
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 403, 'User is banned or an issue occured');
|
||||
}
|
||||
if (!passwordMatch) return await respondWithStatus(res, 401, 'Incorrect password');
|
||||
|
||||
if (isBanned(user.id)) return await respondWithStatus(res, 403, 'User is banned or an issue occured');
|
||||
const token = await generateToken(user.id, password);
|
||||
return await respondWithStatusJSON(res, 200, {
|
||||
message: 'Login successful',
|
||||
token: token,
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
catch (err) {
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
@@ -101,177 +87,27 @@ router.post('/login', requestLimiter, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/verify', async (req, res) => {
|
||||
const { c, u } = req.query;
|
||||
if ([c, u].every(Boolean)) {
|
||||
try {
|
||||
let userId = u;
|
||||
if (!isNumber(u)) {
|
||||
const [user] = await pool.execute(
|
||||
'SELECT id FROM users WHERE username = ? OR email = ? LIMIT 1',
|
||||
[u, u],
|
||||
);
|
||||
if (!user.length) {
|
||||
return await respondWithStatus(res, 404, 'Incorrect username or email');
|
||||
}
|
||||
userId = user[0].id;
|
||||
}
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM user_email_verifications WHERE user_id = ? AND verification_code = ? LIMIT 1',
|
||||
[userId, c],
|
||||
);
|
||||
if (!rows.length) {
|
||||
return await respondWithStatus(res, 400, 'Invalid code');
|
||||
}
|
||||
|
||||
if (rows[0].type == 'register') {
|
||||
const [customerId] = await pool.execute(
|
||||
'SELECT id FROM user_types WHERE name = \'customer\' LIMIT 1',
|
||||
);
|
||||
const [result] = await pool.execute('UPDATE users SET user_type_id = ? WHERE id = ?', [ customerId[0].id, userId ]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating user');
|
||||
}
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Successfully verified user');
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/verify', verifyToken, checkBanned, async (req, res) => {
|
||||
const { code } = req.body;
|
||||
const userId = req.userId;
|
||||
if ([code, userId].every(Boolean)) {
|
||||
try {
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM user_email_verifications WHERE user_id = ? AND verification_code = ? LIMIT 1',
|
||||
[ userId, code ],
|
||||
);
|
||||
if (!rows.length) {
|
||||
return await respondWithStatus(res, 400, 'Invalid code');
|
||||
}
|
||||
const [customerId] = await pool.execute(
|
||||
'SELECT id FROM user_types WHERE name = \'customer\' LIMIT 1',
|
||||
);
|
||||
const [result] = await pool.execute('UPDATE users SET user_type_id = ? WHERE userId = ?', [ customerId[0].id, userId ]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating user');
|
||||
}
|
||||
return await respondWithStatus(res, 200, 'Successfully verified user');
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/changepassword', async (req, res) => {
|
||||
const { usernameOrEmail } = req.body;
|
||||
if ([ usernameOrEmail ].every(Boolean)) {
|
||||
try {
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE email = ? OR username = ? LIMIT 1', [usernameOrEmail, usernameOrEmail]);
|
||||
if (user.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
}
|
||||
|
||||
let code;
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM user_email_verifications WHERE user_id = ? AND type = \'password\' LIMIT 1',
|
||||
[user[0].id],
|
||||
);
|
||||
if (!rows.length) {
|
||||
code = sendResetVerification(user[0].email);
|
||||
}
|
||||
else {
|
||||
code = sendResetVerification(user[0].email, rows[0].verification_code);
|
||||
}
|
||||
|
||||
if (code) {
|
||||
pool.execute('INSERT INTO user_email_verifications (user_id, verification_code, type) VALUES (?, ?, ?)', [ user[0].id, code, 'password' ]);
|
||||
return await respondWithStatus(res, 200, 'Successfully sent password reset email');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/changepassword', async (req, res) => {
|
||||
const { usernameOrEmail, password, code } = req.body;
|
||||
try {
|
||||
const [user] = await pool.execute(
|
||||
'SELECT id FROM users WHERE username = ? OR email = ? LIMIT 1',
|
||||
[usernameOrEmail, usernameOrEmail],
|
||||
);
|
||||
if (!user.length) {
|
||||
return await respondWithStatus(res, 404, 'Incorrect username or email');
|
||||
}
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM user_email_verifications WHERE user_id = ? AND verification_code = ? AND type = \'password\' ORDER BY 1 DESC LIMIT 1',
|
||||
[user[0].id, code],
|
||||
);
|
||||
if (!rows.length) {
|
||||
return await respondWithStatus(res, 400, 'Invalid code');
|
||||
}
|
||||
const [result] = await pool.execute('DELETE FROM user_email_verifications WHERE user_id = ? AND verification_code = ?', [ user[0].id, code ]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing verification');
|
||||
}
|
||||
revokeUserTokens(user[0].id);
|
||||
const token = generateToken(user[0].id, password);
|
||||
res.cookie('token', token, {
|
||||
expires: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'strict',
|
||||
});
|
||||
return userPATCH(res, user[0].id, 'password', password);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/', verifyToken, checkBanned, hasPermission('view_users'), async (req, res) => {
|
||||
router.get('/', verifyToken, checkBanned, checkPermissions('user', 1), async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE 1');
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'Users not found');
|
||||
}
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'Users not found');
|
||||
return await respondWithStatusJSON(res, 200, rows);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', verifyToken, checkBanned, hasPermission('add_users'), async (req, res) => {
|
||||
const { first_name, last_name, username, email, password, user_type } = req.body;
|
||||
if ([first_name, last_name, username, email, password, user_type].every(Boolean)) {
|
||||
router.post('/', verifyToken, checkBanned, checkPermissions('user', 2), async (req, res) => {
|
||||
const { first_name, last_name, username, email, password, phone = 'None' } = req.body;
|
||||
if ([ first_name, last_name, username, email, password ].every(Boolean)) {
|
||||
try {
|
||||
const hashedPassword = await Bun.password.hash(password);
|
||||
await pool.execute(
|
||||
'INSERT INTO users (first_name, last_name, username, email, password, user_type) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ first_name, last_name, username, email, hashedPassword, user_type ],
|
||||
'INSERT INTO users (first_name, last_name, username, email, password, phone) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[ first_name, last_name, username, email, hashedPassword, phone ],
|
||||
);
|
||||
return await respondWithStatus(res, 200, 'User created successfully');
|
||||
}
|
||||
@@ -285,48 +121,10 @@ router.post('/', verifyToken, checkBanned, hasPermission('add_users'), async (re
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/', verifyToken, checkBanned, async (req, res) => {
|
||||
router.get('/:userId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
const { type, value } = req.body;
|
||||
userPATCH(res, userId, type, value);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
const { first_name, last_name, username, email } = req.body;
|
||||
userPUT(res, userId, first_name, last_name, username, email);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
userDELETE(res, userId);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:userId', verifyToken, checkBanned, hasPermission('view_users'), async (req, res) => {
|
||||
try {
|
||||
let userId = req.params.userId;
|
||||
if (req.params.userId == 'me') {
|
||||
userId = req.userId;
|
||||
}
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (req.params.userId != req.userId && !verifyPermissions(req.userId, 'user', 1)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [req.params.userId]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
@@ -336,30 +134,24 @@ router.get('/:userId', verifyToken, checkBanned, hasPermission('view_users'), as
|
||||
return await respondWithStatusJSON(res, 200, user);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.patch('/:userId', verifyToken, checkBanned, hasPermission('edit_users'), async (req, res) => {
|
||||
router.patch('/:userId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.userId;
|
||||
const { type, value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
}
|
||||
if (req.params.userId != req.userId && !verifyPermissions(req.userId, 'user', 2)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
const { type } = req.body;
|
||||
let { value } = req.body;
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [req.params.userId]);
|
||||
if (rows.length === 0) return await respondWithStatus(res, 404, 'User not found');
|
||||
const excludedKeys = ['id'];
|
||||
const fields = rows.map(row =>
|
||||
Object.keys(row)
|
||||
.filter(key => !excludedKeys.includes(key)),
|
||||
);
|
||||
console.log(fields[0]);
|
||||
const fields = rows.map(row => Object.keys(row).filter(key => !excludedKeys.includes(key)));
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE users SET ${type} = ? WHERE id = ?`, [value, userId]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating user');
|
||||
}
|
||||
if (type === 'password') value = await Bun.password.hash(value);
|
||||
const [result] = await pool.execute(`UPDATE users SET ${type} = ? WHERE id = ?`, [value, req.params.userId]);
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating user');
|
||||
return respondWithStatus(res, 200, 'User updated successfully');
|
||||
}
|
||||
else {
|
||||
@@ -367,93 +159,170 @@ router.patch('/:userId', verifyToken, checkBanned, hasPermission('edit_users'),
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:userId', verifyToken, checkBanned, hasPermission('edit_users'), async (req, res) => {
|
||||
router.put('/:userId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.userId;
|
||||
const { first_name, last_name, username, email } = req.body;
|
||||
if (req.params.userId != req.userId && !verifyPermissions(req.userId, 'user', 2)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
const { first_name, last_name, username, password = null, email, phone = null } = req.body;
|
||||
if ([first_name, last_name, username, email].every(Boolean)) {
|
||||
userPUT(res, userId, first_name, last_name, username, email);
|
||||
let sqlQuery = 'UPDATE users SET first_name = ?, last_name = ?, username = ?, email = ?';
|
||||
const queryParams = [first_name, last_name, username, email];
|
||||
if (password) {
|
||||
const hashedPassword = await Bun.password.hash(password);
|
||||
sqlQuery = +' password = ?';
|
||||
queryParams.append(hashedPassword);
|
||||
}
|
||||
else if (phone && isPhoneNumber(phone)) {
|
||||
sqlQuery = ' phone = ?';
|
||||
queryParams.append(phone);
|
||||
}
|
||||
const [result] = await pool.execute(sqlQuery + ' WHERE id = ?', queryParams.append(req.params.userId));
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating user');
|
||||
return respondWithStatus(res, 200, 'User updated successfully');
|
||||
}
|
||||
if (!userExists(req.params.userId)) return await respondWithStatus(res, 404, 'User not found');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:userId', verifyToken, checkBanned, hasPermission('delete_users'), async (req, res) => {
|
||||
router.delete('/:userId', verifyToken, checkBanned, async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.userId;
|
||||
userDELETE(res, userId);
|
||||
if (req.params.userId != req.userId && !verifyPermissions(req.userId, 'user', 4)) return await respondWithStatus(res, 403, 'Missing permission');
|
||||
if (!userExists(req.params.userId)) return await respondWithStatus(res, 404, 'User not found');
|
||||
const [result] = await pool.execute('DELETE FROM users WHERE id = ?', [ req.params.userId ]);
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error removing user');
|
||||
return respondWithStatus(res, 200, 'User deleted successfully');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
});
|
||||
|
||||
async function userPATCH(res, id, type, value) {
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [id]);
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
|
||||
// Email verification endpoints
|
||||
router.get('/email/request', verifyToken, checkBanned, async (req, res) => {
|
||||
const userId = req.userId;
|
||||
try {
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (!rows.length) return await respondWithStatus(res, 404, 'User not found');
|
||||
const user = rows[0];
|
||||
if (user.email_verified) return await respondWithStatus(res, 400, 'Email is already verified');
|
||||
const code = sendVerification(user.email, userId, 'email');
|
||||
pool.execute('INSERT INTO verification_codes (user_id, verification_code, type) VALUES (?, ?, ?)', [ userId, code, 'email' ]);
|
||||
return await respondWithStatus(res, 200, 'Successfully sent verification email');
|
||||
}
|
||||
const excludedKeys = ['id', 'user_type_id', 'is_banned'];
|
||||
const fields = rows.map(row =>
|
||||
Object.keys(row)
|
||||
.filter(key => !excludedKeys.includes(key)),
|
||||
);
|
||||
if (type == 'password') {
|
||||
value = await Bun.password.hash(value);
|
||||
catch (err) {
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
if (fields[0].includes(type)) {
|
||||
const [result] = await pool.execute(`UPDATE users SET ${type} = ? WHERE id = ?`, [value, id]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating user');
|
||||
});
|
||||
|
||||
router.get('/email/verify', verifyToken, checkBanned, async (req, res) => {
|
||||
const { code } = req.query;
|
||||
const userId = req.userId;
|
||||
if (code) {
|
||||
try {
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM verification_codes WHERE user_id = ? AND verification_code = ? AND type = ? AND created_at >= NOW() - INTERVAL 10 MINUTE LIMIT 1',
|
||||
[userId, code, 'email'],
|
||||
);
|
||||
if (!rows.length) return await respondWithStatus(res, 400, 'Invalid code');
|
||||
|
||||
const [result] = await pool.execute('UPDATE users SET email_verified = ? WHERE id = ?', [ true, userId ]);
|
||||
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating user');
|
||||
|
||||
return await respondWithStatus(res, 200, 'Successfully verified user');
|
||||
}
|
||||
catch (err) {
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
return respondWithStatus(res, 200, 'User updated successfully');
|
||||
}
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Invalid type or disallowed');
|
||||
return await respondWithStatus(res, 400, 'Missing code');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function userPUT(res, userId, first_name, last_name, username, email, password = false) {
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
}
|
||||
let sqlQuery, queryParams;
|
||||
if (password) {
|
||||
const hashedPassword = await Bun.password.hash(password);
|
||||
sqlQuery = 'UPDATE users SET first_name = ?, last_name = ?, username = ?, email = ?, password = ? WHERE id = ?';
|
||||
queryParams = [first_name, last_name, username, email, hashedPassword, userId];
|
||||
// Phone verification endpoints (requires a mobile providers API)
|
||||
// POST /phone/request
|
||||
// PATCH /phone/verify
|
||||
|
||||
// Password reset endpoints
|
||||
router.post('/password/request', async (req, res) => {
|
||||
const { usernameOrEmail } = req.body;
|
||||
if (usernameOrEmail) {
|
||||
try {
|
||||
const [user] = await pool.execute('SELECT * FROM users WHERE email = ? OR username = ? LIMIT 1', [usernameOrEmail, usernameOrEmail]);
|
||||
if (user.length === 0) return await respondWithStatus(res, 404, 'User not found');
|
||||
|
||||
let code;
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM verification_codes WHERE user_id = ? AND type = ? AND created_at >= NOW() - INTERVAL 10 MINUTE LIMIT 1', [user[0].id, 'password'],
|
||||
);
|
||||
if (!rows.length) {
|
||||
code = sendVerification(user[0].email, user[0].id, 'password');
|
||||
pool.execute('INSERT INTO verification_codes (user_id, verification_code, type) VALUES (?, ?, ?)', [ user[0].id, code, 'password' ]);
|
||||
return await respondWithStatus(res, 200, 'Successfully sent password reset email');
|
||||
}
|
||||
else {
|
||||
code = sendVerification(user[0].email, user[0].id, 'password', rows[0].verification_code);
|
||||
return await respondWithStatus(res, 200, 'Successfully sent password reset email');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
else {
|
||||
sqlQuery = 'UPDATE users SET first_name = ?, last_name = ?, username = ?, email = ? WHERE id = ?';
|
||||
queryParams = [first_name, last_name, username, email, userId];
|
||||
return await respondWithStatus(res, 400, 'Missing username or email');
|
||||
}
|
||||
const [result] = await pool.execute(sqlQuery, queryParams);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error updating user');
|
||||
}
|
||||
return respondWithStatus(res, 200, 'User updated successfully');
|
||||
}
|
||||
});
|
||||
|
||||
async function userDELETE(res, userId) {
|
||||
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [userId]);
|
||||
if (rows.length === 0) {
|
||||
return await respondWithStatus(res, 404, 'User not found');
|
||||
router.patch('/password/verify', async (req, res) => {
|
||||
const { usernameOrEmail, password, code } = req.body;
|
||||
if ([usernameOrEmail, password, code].every(Boolean)) {
|
||||
try {
|
||||
const [user] = await pool.execute(
|
||||
'SELECT id FROM users WHERE username = ? OR email = ? LIMIT 1',
|
||||
[usernameOrEmail, usernameOrEmail],
|
||||
);
|
||||
if (!user.length) return await respondWithStatus(res, 404, 'Incorrect username or email');
|
||||
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT * FROM verification_codes WHERE user_id = ? AND verification_code = ? AND type = ? AND created_at >= NOW() - INTERVAL 10 MINUTE ORDER BY 1 DESC LIMIT 1',
|
||||
[user[0].id, code, 'password'],
|
||||
);
|
||||
if (!rows.length) return await respondWithStatus(res, 400, 'Invalid code');
|
||||
|
||||
const [result] = await pool.execute('DELETE FROM verification_codes WHERE user_id = ? AND verification_code = ?', [ user[0].id, code ]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing verification');
|
||||
}
|
||||
const token = generateToken(user[0].id, password);
|
||||
const [rest] = await pool.execute('UPDATE users SET password = ? WHERE id = ?', [await Bun.password.hash(password), user[0].id]);
|
||||
if (rest.affectedRows === 0) return await respondWithStatus(res, 500, 'Error updating user');
|
||||
return await respondWithStatusJSON(res, 200, {
|
||||
message: 'Password reset successful',
|
||||
token: token,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
error(err);
|
||||
return await respondWithStatus(res, 500, 'An error has occured');
|
||||
}
|
||||
}
|
||||
const [result] = await pool.execute('DELETE FROM users WHERE id = ?', [ userId ]);
|
||||
if (result.affectedRows === 0) {
|
||||
return await respondWithStatus(res, 500, 'Error removing user');
|
||||
else {
|
||||
return await respondWithStatus(res, 400, 'Missing fields');
|
||||
}
|
||||
return respondWithStatus(res, 200, 'User deleted successfully');
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1 +0,0 @@
|
||||
MANIFEST-000036
|
||||
@@ -1,3 +0,0 @@
|
||||
2023/11/21-19:14:47.768569 7fc5f7fff6c0 Recovering log #35
|
||||
2023/11/21-19:14:47.781678 7fc5f7fff6c0 Delete type=0 #35
|
||||
2023/11/21-19:14:47.781920 7fc5f7fff6c0 Delete type=3 #34
|
||||
@@ -1,3 +0,0 @@
|
||||
2023/03/12-14:35:27.203048 7f7857bff6c0 Recovering log #33
|
||||
2023/03/12-14:35:27.221582 7f7857bff6c0 Delete type=0 #33
|
||||
2023/03/12-14:35:27.221647 7f7857bff6c0 Delete type=3 #32
|
||||
Binary file not shown.
Reference in New Issue
Block a user