@@ -1,232 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import random
|
|
||||||
|
|
||||||
# Connect to the SQLite database
|
|
||||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# Check if we need to add any new categories
|
|
||||||
cursor.execute("SELECT id FROM ecoCategories")
|
|
||||||
existing_categories = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Add two new categories
|
|
||||||
new_categories = [
|
|
||||||
(16, "Urban Farms"),
|
|
||||||
(17, "Rainwater Harvesting Systems")
|
|
||||||
]
|
|
||||||
|
|
||||||
for category in new_categories:
|
|
||||||
if category[0] not in existing_categories:
|
|
||||||
cursor.execute("INSERT INTO ecoCategories (id, name) VALUES (?, ?)", category)
|
|
||||||
print(f"Added new category: {category[1]}")
|
|
||||||
|
|
||||||
# Get list of user IDs for contributors
|
|
||||||
cursor.execute("SELECT id FROM ecoUser")
|
|
||||||
user_ids = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Define 10 new ecological facilities in the UK with accurate location data
|
|
||||||
new_facilities = [
|
|
||||||
{
|
|
||||||
"title": "Community Garden Hackney",
|
|
||||||
"category": 12, # Pollinator Gardens
|
|
||||||
"description": "Urban garden with native plants to support local pollinators",
|
|
||||||
"houseNumber": "45",
|
|
||||||
"streetName": "Dalston Lane",
|
|
||||||
"county": "Greater London",
|
|
||||||
"town": "London",
|
|
||||||
"postcode": "E8 3AH",
|
|
||||||
"lng": -0.0612,
|
|
||||||
"lat": 51.5476,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Recently expanded with new wildflower section",
|
|
||||||
"Volunteer days every Saturday"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Rooftop Solar Farm",
|
|
||||||
"category": 8, # Green Roofs
|
|
||||||
"description": "Combined green roof and solar panel installation on commercial building",
|
|
||||||
"houseNumber": "120",
|
|
||||||
"streetName": "Deansgate",
|
|
||||||
"county": "Greater Manchester",
|
|
||||||
"town": "Manchester",
|
|
||||||
"postcode": "M3 2QJ",
|
|
||||||
"lng": -2.2484,
|
|
||||||
"lat": 53.4808,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Generates power for the entire building"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Edinburgh Tool Library",
|
|
||||||
"category": 15, # Community Tool Libraries
|
|
||||||
"description": "Borrow tools instead of buying them - reducing waste and consumption",
|
|
||||||
"houseNumber": "25",
|
|
||||||
"streetName": "Leith Walk",
|
|
||||||
"county": "Edinburgh",
|
|
||||||
"town": "Edinburgh",
|
|
||||||
"postcode": "EH6 8LN",
|
|
||||||
"lng": -3.1752,
|
|
||||||
"lat": 55.9677,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Cardiff Bay Water Refill Station",
|
|
||||||
"category": 9, # Public Water Refill Stations
|
|
||||||
"description": "Free water refill station to reduce plastic bottle usage",
|
|
||||||
"houseNumber": "3",
|
|
||||||
"streetName": "Mermaid Quay",
|
|
||||||
"county": "Cardiff",
|
|
||||||
"town": "Cardiff",
|
|
||||||
"postcode": "CF10 5BZ",
|
|
||||||
"lng": -3.1644,
|
|
||||||
"lat": 51.4644,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Recently cleaned and maintained",
|
|
||||||
"High usage during summer months"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Bristol Urban Farm",
|
|
||||||
"category": 16, # Urban Farms (new category)
|
|
||||||
"description": "Community-run urban farm providing local produce and education",
|
|
||||||
"houseNumber": "18",
|
|
||||||
"streetName": "Stapleton Road",
|
|
||||||
"county": "Bristol",
|
|
||||||
"town": "Bristol",
|
|
||||||
"postcode": "BS5 0RA",
|
|
||||||
"lng": -2.5677,
|
|
||||||
"lat": 51.4635,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Open for volunteers Tuesday-Sunday"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Newcastle Rainwater Collection System",
|
|
||||||
"category": 17, # Rainwater Harvesting Systems (new category)
|
|
||||||
"description": "Public demonstration of rainwater harvesting for garden irrigation",
|
|
||||||
"houseNumber": "55",
|
|
||||||
"streetName": "Northumberland Street",
|
|
||||||
"county": "Tyne and Wear",
|
|
||||||
"town": "Newcastle upon Tyne",
|
|
||||||
"postcode": "NE1 7DH",
|
|
||||||
"lng": -1.6178,
|
|
||||||
"lat": 54.9783,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Brighton Beach Solar Bench",
|
|
||||||
"category": 7, # Solar-Powered Benches
|
|
||||||
"description": "Solar-powered bench with USB charging ports and WiFi",
|
|
||||||
"houseNumber": "",
|
|
||||||
"streetName": "Kings Road",
|
|
||||||
"county": "East Sussex",
|
|
||||||
"town": "Brighton",
|
|
||||||
"postcode": "BN1 2FN",
|
|
||||||
"lng": -0.1426,
|
|
||||||
"lat": 50.8214,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Popular spot for tourists",
|
|
||||||
"One USB port currently not working"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Leeds Community Compost Hub",
|
|
||||||
"category": 6, # Community Compost Bins
|
|
||||||
"description": "Large-scale community composting facility for local residents",
|
|
||||||
"houseNumber": "78",
|
|
||||||
"streetName": "Woodhouse Lane",
|
|
||||||
"county": "West Yorkshire",
|
|
||||||
"town": "Leeds",
|
|
||||||
"postcode": "LS2 9JT",
|
|
||||||
"lng": -1.5491,
|
|
||||||
"lat": 53.8067,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Recently expanded capacity"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Glasgow EV Charging Hub",
|
|
||||||
"category": 4, # Public EV Charging Stations
|
|
||||||
"description": "Multi-vehicle EV charging station with fast chargers",
|
|
||||||
"houseNumber": "42",
|
|
||||||
"streetName": "Buchanan Street",
|
|
||||||
"county": "Glasgow",
|
|
||||||
"town": "Glasgow",
|
|
||||||
"postcode": "G1 3JX",
|
|
||||||
"lng": -4.2526,
|
|
||||||
"lat": 55.8621,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"6 charging points available",
|
|
||||||
"24/7 access"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Oxford E-Waste Collection Center",
|
|
||||||
"category": 13, # E-Waste Collection Bins
|
|
||||||
"description": "Dedicated facility for proper disposal and recycling of electronic waste",
|
|
||||||
"houseNumber": "15",
|
|
||||||
"streetName": "St Aldate's",
|
|
||||||
"county": "Oxfordshire",
|
|
||||||
"town": "Oxford",
|
|
||||||
"postcode": "OX1 1BX",
|
|
||||||
"lng": -1.2577,
|
|
||||||
"lat": 51.7520,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# Insert facilities into the database
|
|
||||||
for facility in new_facilities:
|
|
||||||
cursor.execute("""
|
|
||||||
INSERT INTO ecoFacilities
|
|
||||||
(title, category, description, houseNumber, streetName, county, town, postcode, lng, lat, contributor)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
""", (
|
|
||||||
facility["title"],
|
|
||||||
facility["category"],
|
|
||||||
facility["description"],
|
|
||||||
facility["houseNumber"],
|
|
||||||
facility["streetName"],
|
|
||||||
facility["county"],
|
|
||||||
facility["town"],
|
|
||||||
facility["postcode"],
|
|
||||||
facility["lng"],
|
|
||||||
facility["lat"],
|
|
||||||
facility["contributor"]
|
|
||||||
))
|
|
||||||
|
|
||||||
# Get the ID of the inserted facility
|
|
||||||
facility_id = cursor.lastrowid
|
|
||||||
|
|
||||||
# Add status comments if any
|
|
||||||
for comment in facility["status_comments"]:
|
|
||||||
cursor.execute("""
|
|
||||||
INSERT INTO ecoFacilityStatus (facilityId, statusComment)
|
|
||||||
VALUES (?, ?)
|
|
||||||
""", (facility_id, comment))
|
|
||||||
|
|
||||||
print(f"Added facility: {facility['title']} in {facility['town']}")
|
|
||||||
|
|
||||||
# Commit the changes and close the connection
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
print("\nSuccessfully added 10 new ecological facilities to the database.")
|
|
||||||
|
|
||||||
Using the test data in the ecoCategories, ecoFacilities, and ecoFacilityStatus, please create 10 new ecological facilities with the following constraints:
|
|
||||||
Must be located in the United Kingdom (Names of areas, towns, cities, counties)
|
|
||||||
Postcode, Latitude and Longitude must be fairly accurate to the location you have generated for the area.
|
|
||||||
More categories may be made, it is up to you, but make sure foreign keys are respected.
|
|
||||||
Contributor may be of any user in the database.
|
|
||||||
Not all facilities must have statusComments, however facilities may have multiple statusComments.
|
|
Binary file not shown.
Binary file not shown.
@@ -1,66 +0,0 @@
|
|||||||
Starting facility generation at 2025-03-20 12:34:00.832910
|
|
||||||
Target: 1000 new facilities
|
|
||||||
|
|
||||||
Generating facilities...
|
|
||||||
Generated 100 facilities so far...
|
|
||||||
Generated 200 facilities so far...
|
|
||||||
Generated 300 facilities so far...
|
|
||||||
Generated 400 facilities so far...
|
|
||||||
Generated 500 facilities so far...
|
|
||||||
Generated 600 facilities so far...
|
|
||||||
Generated 700 facilities so far...
|
|
||||||
Generated 800 facilities so far...
|
|
||||||
Generated 900 facilities so far...
|
|
||||||
Generated 1000 facilities so far...
|
|
||||||
|
|
||||||
Inserting facilities into database...
|
|
||||||
Inserted batch 1/20
|
|
||||||
Inserted batch 2/20
|
|
||||||
Inserted batch 3/20
|
|
||||||
Inserted batch 4/20
|
|
||||||
Inserted batch 5/20
|
|
||||||
Inserted batch 6/20
|
|
||||||
Inserted batch 7/20
|
|
||||||
Inserted batch 8/20
|
|
||||||
Inserted batch 9/20
|
|
||||||
Inserted batch 10/20
|
|
||||||
Inserted batch 11/20
|
|
||||||
Inserted batch 12/20
|
|
||||||
Inserted batch 13/20
|
|
||||||
Inserted batch 14/20
|
|
||||||
Inserted batch 15/20
|
|
||||||
Inserted batch 16/20
|
|
||||||
Inserted batch 17/20
|
|
||||||
Inserted batch 18/20
|
|
||||||
Inserted batch 19/20
|
|
||||||
Inserted batch 20/20
|
|
||||||
|
|
||||||
Inserting status comments...
|
|
||||||
Inserted comment batch 1/23
|
|
||||||
Inserted comment batch 2/23
|
|
||||||
Inserted comment batch 3/23
|
|
||||||
Inserted comment batch 4/23
|
|
||||||
Inserted comment batch 5/23
|
|
||||||
Inserted comment batch 6/23
|
|
||||||
Inserted comment batch 7/23
|
|
||||||
Inserted comment batch 8/23
|
|
||||||
Inserted comment batch 9/23
|
|
||||||
Inserted comment batch 10/23
|
|
||||||
Inserted comment batch 11/23
|
|
||||||
Inserted comment batch 12/23
|
|
||||||
Inserted comment batch 13/23
|
|
||||||
Inserted comment batch 14/23
|
|
||||||
Inserted comment batch 15/23
|
|
||||||
Inserted comment batch 16/23
|
|
||||||
Inserted comment batch 17/23
|
|
||||||
Inserted comment batch 18/23
|
|
||||||
Inserted comment batch 19/23
|
|
||||||
Inserted comment batch 20/23
|
|
||||||
Inserted comment batch 21/23
|
|
||||||
Inserted comment batch 22/23
|
|
||||||
Inserted comment batch 23/23
|
|
||||||
|
|
||||||
Generation complete at 2025-03-20 12:34:00.860477
|
|
||||||
Total facilities in database: 12025
|
|
||||||
Total status comments in database: 13385
|
|
||||||
Generated facilities saved to generated_facilities.csv for reference
|
|
@@ -1,568 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import random
|
|
||||||
import csv
|
|
||||||
import os
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
# Connect to the SQLite database
|
|
||||||
conn = sqlite3.connect('ecobuddy.sqlite')
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# Get current max facility ID
|
|
||||||
cursor.execute("SELECT MAX(id) FROM ecoFacilities")
|
|
||||||
max_facility_id = cursor.fetchone()[0] or 0
|
|
||||||
|
|
||||||
# Get list of user IDs for contributors
|
|
||||||
cursor.execute("SELECT id FROM ecoUser")
|
|
||||||
user_ids = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Get list of categories
|
|
||||||
cursor.execute("SELECT id, name FROM ecoCategories")
|
|
||||||
categories = {row[0]: row[1] for row in cursor.fetchall()}
|
|
||||||
|
|
||||||
# UK Cities and Towns with their counties and approximate coordinates
|
|
||||||
uk_locations = [
|
|
||||||
# Format: Town/City, County, Latitude, Longitude, Postcode Area
|
|
||||||
("London", "Greater London", 51.5074, -0.1278, "EC"),
|
|
||||||
("Birmingham", "West Midlands", 52.4862, -1.8904, "B"),
|
|
||||||
("Manchester", "Greater Manchester", 53.4808, -2.2426, "M"),
|
|
||||||
("Glasgow", "Glasgow", 55.8642, -4.2518, "G"),
|
|
||||||
("Liverpool", "Merseyside", 53.4084, -2.9916, "L"),
|
|
||||||
("Bristol", "Bristol", 51.4545, -2.5879, "BS"),
|
|
||||||
("Edinburgh", "Edinburgh", 55.9533, -3.1883, "EH"),
|
|
||||||
("Leeds", "West Yorkshire", 53.8008, -1.5491, "LS"),
|
|
||||||
("Sheffield", "South Yorkshire", 53.3811, -1.4701, "S"),
|
|
||||||
("Newcastle upon Tyne", "Tyne and Wear", 54.9783, -1.6178, "NE"),
|
|
||||||
("Nottingham", "Nottinghamshire", 52.9548, -1.1581, "NG"),
|
|
||||||
("Cardiff", "Cardiff", 51.4816, -3.1791, "CF"),
|
|
||||||
("Belfast", "Belfast", 54.5973, -5.9301, "BT"),
|
|
||||||
("Brighton", "East Sussex", 50.8225, -0.1372, "BN"),
|
|
||||||
("Leicester", "Leicestershire", 52.6369, -1.1398, "LE"),
|
|
||||||
("Aberdeen", "Aberdeen", 57.1497, -2.0943, "AB"),
|
|
||||||
("Portsmouth", "Hampshire", 50.8198, -1.0880, "PO"),
|
|
||||||
("York", "North Yorkshire", 53.9599, -1.0873, "YO"),
|
|
||||||
("Swansea", "Swansea", 51.6214, -3.9436, "SA"),
|
|
||||||
("Oxford", "Oxfordshire", 51.7520, -1.2577, "OX"),
|
|
||||||
("Cambridge", "Cambridgeshire", 52.2053, 0.1218, "CB"),
|
|
||||||
("Exeter", "Devon", 50.7184, -3.5339, "EX"),
|
|
||||||
("Bath", "Somerset", 51.3751, -2.3617, "BA"),
|
|
||||||
("Reading", "Berkshire", 51.4543, -0.9781, "RG"),
|
|
||||||
("Preston", "Lancashire", 53.7632, -2.7031, "PR"),
|
|
||||||
("Coventry", "West Midlands", 52.4068, -1.5197, "CV"),
|
|
||||||
("Hull", "East Yorkshire", 53.7676, -0.3274, "HU"),
|
|
||||||
("Stoke-on-Trent", "Staffordshire", 53.0027, -2.1794, "ST"),
|
|
||||||
("Wolverhampton", "West Midlands", 52.5870, -2.1288, "WV"),
|
|
||||||
("Plymouth", "Devon", 50.3755, -4.1427, "PL"),
|
|
||||||
("Derby", "Derbyshire", 52.9225, -1.4746, "DE"),
|
|
||||||
("Sunderland", "Tyne and Wear", 54.9069, -1.3830, "SR"),
|
|
||||||
("Southampton", "Hampshire", 50.9097, -1.4044, "SO"),
|
|
||||||
("Norwich", "Norfolk", 52.6309, 1.2974, "NR"),
|
|
||||||
("Bournemouth", "Dorset", 50.7192, -1.8808, "BH"),
|
|
||||||
("Middlesbrough", "North Yorkshire", 54.5742, -1.2350, "TS"),
|
|
||||||
("Blackpool", "Lancashire", 53.8175, -3.0357, "FY"),
|
|
||||||
("Bolton", "Greater Manchester", 53.5785, -2.4299, "BL"),
|
|
||||||
("Ipswich", "Suffolk", 52.0567, 1.1482, "IP"),
|
|
||||||
("Telford", "Shropshire", 52.6784, -2.4453, "TF"),
|
|
||||||
("Dundee", "Dundee", 56.4620, -2.9707, "DD"),
|
|
||||||
("Peterborough", "Cambridgeshire", 52.5695, -0.2405, "PE"),
|
|
||||||
("Huddersfield", "West Yorkshire", 53.6458, -1.7850, "HD"),
|
|
||||||
("Luton", "Bedfordshire", 51.8787, -0.4200, "LU"),
|
|
||||||
("Warrington", "Cheshire", 53.3900, -2.5970, "WA"),
|
|
||||||
("Southend-on-Sea", "Essex", 51.5459, 0.7077, "SS"),
|
|
||||||
("Swindon", "Wiltshire", 51.5557, -1.7797, "SN"),
|
|
||||||
("Slough", "Berkshire", 51.5105, -0.5950, "SL"),
|
|
||||||
("Watford", "Hertfordshire", 51.6565, -0.3903, "WD"),
|
|
||||||
("Carlisle", "Cumbria", 54.8952, -2.9335, "CA")
|
|
||||||
]
|
|
||||||
|
|
||||||
# Street name components for generating realistic street names
|
|
||||||
street_prefixes = ["High", "Main", "Church", "Park", "Mill", "Station", "London", "Victoria", "Queen", "King", "North", "South", "East", "West", "New", "Old", "Castle", "Bridge", "Green", "Market", "School", "Manor", "Abbey", "Priory", "Cathedral", "University", "College", "Hospital", "Railway", "Canal", "River", "Forest", "Wood", "Hill", "Mount", "Valley", "Meadow", "Field", "Farm", "Garden", "Orchard", "Vineyard", "Grange", "Lodge", "Court", "Hall", "House", "Cottage", "Barn", "Mill", "Windmill", "Watermill", "Forge", "Quarry", "Mine", "Pit", "Well", "Spring", "Brook", "Stream", "Lake", "Pond", "Pool", "Reservoir", "Bay", "Cove", "Beach", "Cliff", "Rock", "Stone", "Granite", "Marble", "Slate", "Clay", "Sand", "Gravel", "Chalk", "Flint", "Coal", "Iron", "Steel", "Copper", "Silver", "Gold", "Tin", "Lead", "Zinc", "Brass", "Bronze", "Pewter", "Nickel", "Cobalt", "Chromium", "Titanium", "Aluminium", "Silicon", "Carbon", "Oxygen", "Hydrogen", "Nitrogen", "Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon"]
|
|
||||||
street_suffixes = ["Street", "Road", "Lane", "Avenue", "Drive", "Boulevard", "Way", "Place", "Square", "Court", "Terrace", "Close", "Crescent", "Gardens", "Grove", "Mews", "Alley", "Walk", "Path", "Trail", "Hill", "Rise", "View", "Heights", "Park", "Green", "Meadow", "Field", "Common", "Heath", "Moor", "Down", "Fell", "Pike", "Tor", "Crag", "Cliff", "Ridge", "Edge", "Top", "Bottom", "Side", "End", "Corner", "Junction", "Cross", "Gate", "Bridge", "Ford", "Ferry", "Wharf", "Quay", "Dock", "Harbor", "Port", "Bay", "Cove", "Beach", "Shore", "Bank", "Strand", "Esplanade", "Parade", "Promenade", "Embankment", "Causeway", "Viaduct", "Tunnel", "Passage", "Arcade", "Gallery", "Mall", "Market", "Bazaar", "Fair", "Exchange", "Mart", "Emporium", "Center", "Circle", "Oval", "Triangle", "Pentagon", "Hexagon", "Octagon", "Circus", "Ring", "Loop", "Bend", "Curve", "Turn", "Twist", "Spiral", "Coil", "Helix", "Maze", "Labyrinth"]
|
|
||||||
|
|
||||||
# Facility descriptions by category
|
|
||||||
category_descriptions = {
|
|
||||||
1: [ # Recycling Bins
|
|
||||||
"Public recycling point for paper, glass, plastic, and metal",
|
|
||||||
"Community recycling station with separate bins for different materials",
|
|
||||||
"Recycling center with facilities for household waste separation",
|
|
||||||
"Public access recycling bins for common household recyclables",
|
|
||||||
"Multi-material recycling point with clear instructions for proper sorting"
|
|
||||||
],
|
|
||||||
2: [ # e-Scooters
|
|
||||||
"Dockless e-scooter rental station with multiple vehicles available",
|
|
||||||
"E-scooter parking and charging zone for public use",
|
|
||||||
"Designated e-scooter pickup and drop-off point",
|
|
||||||
"E-scooter sharing station with app-based rental system",
|
|
||||||
"Electric scooter hub with maintenance and charging facilities"
|
|
||||||
],
|
|
||||||
3: [ # Bike Share Stations
|
|
||||||
"Public bicycle sharing station with multiple bikes available",
|
|
||||||
"Bike rental hub with secure docking stations",
|
|
||||||
"Community bike share point with regular and electric bicycles",
|
|
||||||
"Cycle hire station with self-service rental system",
|
|
||||||
"Bike sharing facility with maintenance and repair services"
|
|
||||||
],
|
|
||||||
4: [ # Public EV Charging Stations
|
|
||||||
"Electric vehicle charging point with multiple connectors",
|
|
||||||
"Fast-charging station for electric vehicles",
|
|
||||||
"Public EV charging facility with covered waiting area",
|
|
||||||
"Multi-vehicle electric charging hub with different power options",
|
|
||||||
"EV charging station with renewable energy source"
|
|
||||||
],
|
|
||||||
5: [ # Battery Recycling Points
|
|
||||||
"Dedicated collection point for used batteries of all sizes",
|
|
||||||
"Battery recycling bin with separate compartments for different types",
|
|
||||||
"Safe disposal facility for household and small electronics batteries",
|
|
||||||
"Battery collection point with educational information about recycling",
|
|
||||||
"Secure battery recycling station to prevent environmental contamination"
|
|
||||||
],
|
|
||||||
6: [ # Community Compost Bins
|
|
||||||
"Neighborhood composting facility for food and garden waste",
|
|
||||||
"Community compost bins with educational signage",
|
|
||||||
"Public composting station with separate sections for different stages",
|
|
||||||
"Shared compost facility managed by local volunteers",
|
|
||||||
"Urban composting hub turning food waste into valuable soil"
|
|
||||||
],
|
|
||||||
7: [ # Solar-Powered Benches
|
|
||||||
"Solar bench with USB charging ports and WiFi connectivity",
|
|
||||||
"Public seating with integrated solar panels and device charging",
|
|
||||||
"Smart bench powered by solar energy with digital information display",
|
|
||||||
"Solar-powered rest area with phone charging capabilities",
|
|
||||||
"Eco-friendly bench with solar panels and LED lighting"
|
|
||||||
],
|
|
||||||
8: [ # Green Roofs
|
|
||||||
"Building with extensive green roof system visible from public areas",
|
|
||||||
"Accessible green roof garden with native plant species",
|
|
||||||
"Public building showcasing sustainable rooftop vegetation",
|
|
||||||
"Green roof installation with educational tours available",
|
|
||||||
"Biodiverse roof garden with insect habitats and rainwater collection"
|
|
||||||
],
|
|
||||||
9: [ # Public Water Refill Stations
|
|
||||||
"Free water refill station to reduce plastic bottle usage",
|
|
||||||
"Public drinking fountain with bottle filling capability",
|
|
||||||
"Water refill point with filtered water options",
|
|
||||||
"Accessible water station encouraging reusable bottles",
|
|
||||||
"Community water dispenser with usage counter display"
|
|
||||||
],
|
|
||||||
10: [ # Waste Oil Collection Points
|
|
||||||
"Cooking oil recycling point for residential use",
|
|
||||||
"Used oil collection facility with secure containers",
|
|
||||||
"Waste oil drop-off point for conversion to biodiesel",
|
|
||||||
"Community oil recycling station with spill prevention measures",
|
|
||||||
"Cooking oil collection facility with educational information"
|
|
||||||
],
|
|
||||||
11: [ # Book Swap Stations
|
|
||||||
"Community book exchange point with weatherproof shelving",
|
|
||||||
"Public book sharing library in repurposed phone box",
|
|
||||||
"Free book swap station encouraging reading and reuse",
|
|
||||||
"Neighborhood book exchange with rotating collection",
|
|
||||||
"Little free library with take-one-leave-one system"
|
|
||||||
],
|
|
||||||
12: [ # Pollinator Gardens
|
|
||||||
"Public garden designed to support bees and butterflies",
|
|
||||||
"Pollinator-friendly planting area with native flowering species",
|
|
||||||
"Community garden dedicated to supporting local insect populations",
|
|
||||||
"Bee-friendly garden with educational signage about pollinators",
|
|
||||||
"Urban wildflower meadow supporting biodiversity"
|
|
||||||
],
|
|
||||||
13: [ # E-Waste Collection Bins
|
|
||||||
"Secure collection point for electronic waste and small appliances",
|
|
||||||
"E-waste recycling bin for phones, computers, and small electronics",
|
|
||||||
"Electronic waste drop-off point with data security assurance",
|
|
||||||
"Community e-waste collection facility with regular collection schedule",
|
|
||||||
"Dedicated bin for responsible disposal of electronic items"
|
|
||||||
],
|
|
||||||
14: [ # Clothing Donation Bins
|
|
||||||
"Textile recycling point for clothes and household fabrics",
|
|
||||||
"Clothing donation bin supporting local charities",
|
|
||||||
"Secure collection point for reusable clothing and textiles",
|
|
||||||
"Community clothing recycling bin with regular collection",
|
|
||||||
"Textile donation point preventing landfill waste"
|
|
||||||
],
|
|
||||||
15: [ # Community Tool Libraries
|
|
||||||
"Tool lending library for community use and sharing",
|
|
||||||
"Shared equipment facility reducing need for individual ownership",
|
|
||||||
"Community resource center for borrowing tools and equipment",
|
|
||||||
"Tool sharing hub with membership system and workshops",
|
|
||||||
"Public tool library with wide range of equipment available"
|
|
||||||
],
|
|
||||||
16: [ # Urban Farms
|
|
||||||
"Community-run urban farm providing local produce",
|
|
||||||
"City farming project with volunteer opportunities",
|
|
||||||
"Urban agriculture site with educational programs",
|
|
||||||
"Local food growing initiative in repurposed urban space",
|
|
||||||
"Community garden with vegetable plots and fruit trees"
|
|
||||||
],
|
|
||||||
17: [ # Rainwater Harvesting Systems
|
|
||||||
"Public demonstration of rainwater collection for irrigation",
|
|
||||||
"Rainwater harvesting system with educational displays",
|
|
||||||
"Community rainwater collection facility for shared gardens",
|
|
||||||
"Visible rainwater storage and filtration system",
|
|
||||||
"Urban water conservation project with storage tanks"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Status comments by category
|
|
||||||
status_comments = {
|
|
||||||
1: [ # Recycling Bins
|
|
||||||
"Recently emptied and cleaned",
|
|
||||||
"Some bins are nearly full",
|
|
||||||
"All bins in good condition",
|
|
||||||
"Paper bin is currently full",
|
|
||||||
"New signage installed to improve sorting"
|
|
||||||
],
|
|
||||||
2: [ # e-Scooters
|
|
||||||
"All scooters fully charged",
|
|
||||||
"Three scooters currently available",
|
|
||||||
"Maintenance scheduled for next week",
|
|
||||||
"New scooters added to this location",
|
|
||||||
"High usage area, scooters frequently unavailable"
|
|
||||||
],
|
|
||||||
3: [ # Bike Share Stations
|
|
||||||
"All docking stations operational",
|
|
||||||
"Five bikes currently available",
|
|
||||||
"Some bikes need maintenance",
|
|
||||||
"New electric bikes added",
|
|
||||||
"Popular station with high turnover"
|
|
||||||
],
|
|
||||||
4: [ # Public EV Charging Stations
|
|
||||||
"All charging points operational",
|
|
||||||
"Fast charger currently under repair",
|
|
||||||
"Peak usage during business hours",
|
|
||||||
"New charging point added last month",
|
|
||||||
"Payment system recently upgraded"
|
|
||||||
],
|
|
||||||
5: [ # Battery Recycling Points
|
|
||||||
"Collection bin recently emptied",
|
|
||||||
"Secure container in good condition",
|
|
||||||
"New signage explaining battery types",
|
|
||||||
"High usage from local businesses",
|
|
||||||
"Additional capacity added"
|
|
||||||
],
|
|
||||||
6: [ # Community Compost Bins
|
|
||||||
"Compost ready for collection",
|
|
||||||
"Needs more brown material",
|
|
||||||
"Recently turned and aerated",
|
|
||||||
"New bins added to increase capacity",
|
|
||||||
"Volunteer day scheduled for maintenance"
|
|
||||||
],
|
|
||||||
7: [ # Solar-Powered Benches
|
|
||||||
"All charging ports working",
|
|
||||||
"Solar panels recently cleaned",
|
|
||||||
"WiFi currently unavailable",
|
|
||||||
"LED lights need replacement",
|
|
||||||
"High usage during lunch hours"
|
|
||||||
],
|
|
||||||
8: [ # Green Roofs
|
|
||||||
"Plants thriving after recent rain",
|
|
||||||
"Maintenance scheduled next month",
|
|
||||||
"New species added to increase biodiversity",
|
|
||||||
"Irrigation system working well",
|
|
||||||
"Open for public tours on weekends"
|
|
||||||
],
|
|
||||||
9: [ # Public Water Refill Stations
|
|
||||||
"Water quality tested weekly",
|
|
||||||
"Fountain cleaned daily",
|
|
||||||
"Bottle filler counter shows high usage",
|
|
||||||
"New filter installed recently",
|
|
||||||
"Popular during summer months"
|
|
||||||
],
|
|
||||||
10: [ # Waste Oil Collection Points
|
|
||||||
"Container recently emptied",
|
|
||||||
"Secure lid in good condition",
|
|
||||||
"New funnel system installed",
|
|
||||||
"Collection schedule posted",
|
|
||||||
"Area kept clean and tidy"
|
|
||||||
],
|
|
||||||
11: [ # Book Swap Stations
|
|
||||||
"Good selection currently available",
|
|
||||||
"Children's books needed",
|
|
||||||
"Recently reorganized by volunteers",
|
|
||||||
"Weatherproof cover working well",
|
|
||||||
"High turnover of popular titles"
|
|
||||||
],
|
|
||||||
12: [ # Pollinator Gardens
|
|
||||||
"Plants in full bloom",
|
|
||||||
"Many bees and butterflies observed",
|
|
||||||
"New native species planted",
|
|
||||||
"Volunteer day for maintenance scheduled",
|
|
||||||
"Educational tours available"
|
|
||||||
],
|
|
||||||
13: [ # E-Waste Collection Bins
|
|
||||||
"Bin recently emptied",
|
|
||||||
"Secure deposit system working",
|
|
||||||
"Collection schedule posted",
|
|
||||||
"New items accepted now include small appliances",
|
|
||||||
"Data destruction guaranteed"
|
|
||||||
],
|
|
||||||
14: [ # Clothing Donation Bins
|
|
||||||
"Bin recently emptied",
|
|
||||||
"Clean and well-maintained",
|
|
||||||
"High quality donations appreciated",
|
|
||||||
"Winter clothing especially needed",
|
|
||||||
"Please bag items before donating"
|
|
||||||
],
|
|
||||||
15: [ # Community Tool Libraries
|
|
||||||
"New inventory system implemented",
|
|
||||||
"Popular tools often unavailable on weekends",
|
|
||||||
"Tool maintenance workshop scheduled",
|
|
||||||
"New donations recently added to collection",
|
|
||||||
"Extended hours during summer"
|
|
||||||
],
|
|
||||||
16: [ # Urban Farms
|
|
||||||
"Seasonal produce currently available",
|
|
||||||
"Volunteer opportunities posted",
|
|
||||||
"Educational workshops on weekends",
|
|
||||||
"New growing area being developed",
|
|
||||||
"Composting system recently expanded"
|
|
||||||
],
|
|
||||||
17: [ # Rainwater Harvesting Systems
|
|
||||||
"System working efficiently after recent rainfall",
|
|
||||||
"Water quality monitoring in place",
|
|
||||||
"Educational tours available by appointment",
|
|
||||||
"System capacity recently expanded",
|
|
||||||
"Used for irrigation of nearby community garden"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate a realistic UK postcode based on area code
|
|
||||||
def generate_postcode(area_code):
|
|
||||||
# Format: Area + District + Space + Sector + Unit
|
|
||||||
# e.g., M1 1AA or SW1A 1AA
|
|
||||||
district = random.randint(1, 99)
|
|
||||||
sector = random.randint(1, 9)
|
|
||||||
unit = ''.join(random.choices('ABCDEFGHJKLMNPQRSTUVWXYZ', k=2)) # Excluding I and O as they're not used
|
|
||||||
|
|
||||||
if len(area_code) == 1:
|
|
||||||
return f"{area_code}{district} {sector}{unit}"
|
|
||||||
else:
|
|
||||||
return f"{area_code}{district} {sector}{unit}"
|
|
||||||
|
|
||||||
# Generate a realistic street name
|
|
||||||
def generate_street_name():
|
|
||||||
prefix = random.choice(street_prefixes)
|
|
||||||
suffix = random.choice(street_suffixes)
|
|
||||||
return f"{prefix} {suffix}"
|
|
||||||
|
|
||||||
# Generate a realistic house number
|
|
||||||
def generate_house_number():
|
|
||||||
# 80% chance of a simple number, 20% chance of a letter suffix or unit
|
|
||||||
if random.random() < 0.8:
|
|
||||||
return str(random.randint(1, 200))
|
|
||||||
else:
|
|
||||||
options = [
|
|
||||||
f"{random.randint(1, 200)}{random.choice('ABCDEFG')}", # e.g., 42A
|
|
||||||
f"Unit {random.randint(1, 20)}",
|
|
||||||
f"Flat {random.randint(1, 50)}",
|
|
||||||
f"Suite {random.randint(1, 10)}"
|
|
||||||
]
|
|
||||||
return random.choice(options)
|
|
||||||
|
|
||||||
# Add small random variation to coordinates to avoid facilities at exact same location
|
|
||||||
def vary_coordinates(lat, lng):
|
|
||||||
# Add variation of up to ~500 meters
|
|
||||||
lat_variation = random.uniform(-0.004, 0.004)
|
|
||||||
lng_variation = random.uniform(-0.006, 0.006)
|
|
||||||
return lat + lat_variation, lng + lng_variation
|
|
||||||
|
|
||||||
# Generate facility title based on category and location
|
|
||||||
def generate_title(category_name, location_name, street_name):
|
|
||||||
templates = [
|
|
||||||
f"{location_name} {category_name}",
|
|
||||||
f"{category_name} at {street_name}",
|
|
||||||
f"{street_name} {category_name}",
|
|
||||||
f"Community {category_name} {location_name}",
|
|
||||||
f"{location_name} Central {category_name}",
|
|
||||||
f"{location_name} {street_name} {category_name}"
|
|
||||||
]
|
|
||||||
return random.choice(templates)
|
|
||||||
|
|
||||||
# Create a log file to track progress
|
|
||||||
log_file = open("facility_generation_log.txt", "w")
|
|
||||||
log_file.write(f"Starting facility generation at {datetime.now()}\n")
|
|
||||||
log_file.write(f"Target: 1000 new facilities\n\n")
|
|
||||||
|
|
||||||
# Create a CSV file to store all generated facilities for reference
|
|
||||||
csv_file = open("generated_facilities.csv", "w", newline='')
|
|
||||||
csv_writer = csv.writer(csv_file)
|
|
||||||
csv_writer.writerow(["ID", "Title", "Category", "Description", "Address", "Postcode", "Latitude", "Longitude", "Contributor"])
|
|
||||||
|
|
||||||
# Prepare for batch insertion to improve performance
|
|
||||||
facilities_to_insert = []
|
|
||||||
status_comments_to_insert = []
|
|
||||||
|
|
||||||
# Track unique titles to avoid duplicates
|
|
||||||
existing_titles = set()
|
|
||||||
cursor.execute("SELECT title FROM ecoFacilities")
|
|
||||||
for row in cursor.fetchall():
|
|
||||||
existing_titles.add(row[0])
|
|
||||||
|
|
||||||
# Generate 1000 facilities
|
|
||||||
num_facilities = 1000
|
|
||||||
facilities_created = 0
|
|
||||||
|
|
||||||
log_file.write("Generating facilities...\n")
|
|
||||||
|
|
||||||
while facilities_created < num_facilities:
|
|
||||||
# Select a random location
|
|
||||||
location = random.choice(uk_locations)
|
|
||||||
location_name, county, base_lat, base_lng, postcode_area = location
|
|
||||||
|
|
||||||
# Generate 5-25 facilities per location to create clusters
|
|
||||||
facilities_per_location = min(random.randint(5, 25), num_facilities - facilities_created)
|
|
||||||
|
|
||||||
for _ in range(facilities_per_location):
|
|
||||||
# Select a random category
|
|
||||||
category_id = random.choice(list(categories.keys()))
|
|
||||||
category_name = categories[category_id]
|
|
||||||
|
|
||||||
# Generate address components
|
|
||||||
street_name = generate_street_name()
|
|
||||||
house_number = generate_house_number()
|
|
||||||
lat, lng = vary_coordinates(base_lat, base_lng)
|
|
||||||
postcode = generate_postcode(postcode_area)
|
|
||||||
|
|
||||||
# Generate title
|
|
||||||
title_base = generate_title(category_name, location_name, street_name)
|
|
||||||
title = title_base
|
|
||||||
|
|
||||||
# Ensure title is unique by adding a suffix if needed
|
|
||||||
suffix = 2
|
|
||||||
while title in existing_titles:
|
|
||||||
title = f"{title_base} {suffix}"
|
|
||||||
suffix += 1
|
|
||||||
|
|
||||||
existing_titles.add(title)
|
|
||||||
|
|
||||||
# Select description
|
|
||||||
description = random.choice(category_descriptions[category_id])
|
|
||||||
|
|
||||||
# Select contributor
|
|
||||||
contributor_id = random.choice(user_ids)
|
|
||||||
|
|
||||||
# Add to batch for insertion
|
|
||||||
facilities_to_insert.append((
|
|
||||||
title,
|
|
||||||
category_id,
|
|
||||||
description,
|
|
||||||
house_number,
|
|
||||||
street_name,
|
|
||||||
county,
|
|
||||||
location_name,
|
|
||||||
postcode,
|
|
||||||
lng,
|
|
||||||
lat,
|
|
||||||
contributor_id
|
|
||||||
))
|
|
||||||
|
|
||||||
# Log progress periodically
|
|
||||||
facilities_created += 1
|
|
||||||
if facilities_created % 100 == 0:
|
|
||||||
log_message = f"Generated {facilities_created} facilities so far..."
|
|
||||||
print(log_message)
|
|
||||||
log_file.write(log_message + "\n")
|
|
||||||
|
|
||||||
if facilities_created >= num_facilities:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Insert facilities in batches for better performance
|
|
||||||
log_file.write("\nInserting facilities into database...\n")
|
|
||||||
print("Inserting facilities into database...")
|
|
||||||
|
|
||||||
batch_size = 50
|
|
||||||
for i in range(0, len(facilities_to_insert), batch_size):
|
|
||||||
batch = facilities_to_insert[i:i+batch_size]
|
|
||||||
cursor.executemany("""
|
|
||||||
INSERT INTO ecoFacilities
|
|
||||||
(title, category, description, houseNumber, streetName, county, town, postcode, lng, lat, contributor)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
""", batch)
|
|
||||||
|
|
||||||
# Get the IDs of the inserted facilities
|
|
||||||
cursor.execute("SELECT last_insert_rowid()")
|
|
||||||
last_id = cursor.fetchone()[0]
|
|
||||||
first_id_in_batch = last_id - len(batch) + 1
|
|
||||||
|
|
||||||
# Generate status comments for each facility
|
|
||||||
for j, facility in enumerate(batch):
|
|
||||||
facility_id = first_id_in_batch + j
|
|
||||||
category_id = facility[1] # Category ID is the second element
|
|
||||||
|
|
||||||
# Write to CSV for reference
|
|
||||||
csv_writer.writerow([
|
|
||||||
facility_id,
|
|
||||||
facility[0], # title
|
|
||||||
categories[category_id], # category name
|
|
||||||
facility[2], # description
|
|
||||||
f"{facility[3]} {facility[4]}, {facility[6]}, {facility[5]}", # address
|
|
||||||
facility[7], # postcode
|
|
||||||
facility[9], # lat
|
|
||||||
facility[8], # lng
|
|
||||||
facility[10] # contributor
|
|
||||||
])
|
|
||||||
|
|
||||||
# Decide how many status comments to add (0-3)
|
|
||||||
num_comments = random.choices([0, 1, 2, 3], weights=[30, 40, 20, 10])[0]
|
|
||||||
|
|
||||||
if num_comments > 0:
|
|
||||||
# Get relevant comments for this category
|
|
||||||
relevant_comments = status_comments.get(category_id, status_comments[1]) # Default to recycling bin comments
|
|
||||||
|
|
||||||
# Select random comments without repetition
|
|
||||||
selected_comments = random.sample(relevant_comments, min(num_comments, len(relevant_comments)))
|
|
||||||
|
|
||||||
# Add to batch for insertion
|
|
||||||
for comment in selected_comments:
|
|
||||||
status_comments_to_insert.append((facility_id, comment))
|
|
||||||
|
|
||||||
# Commit after each batch
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
log_message = f"Inserted batch {i//batch_size + 1}/{(len(facilities_to_insert)-1)//batch_size + 1}"
|
|
||||||
print(log_message)
|
|
||||||
log_file.write(log_message + "\n")
|
|
||||||
|
|
||||||
# Insert status comments in batches
|
|
||||||
if status_comments_to_insert:
|
|
||||||
log_file.write("\nInserting status comments...\n")
|
|
||||||
print("Inserting status comments...")
|
|
||||||
|
|
||||||
for i in range(0, len(status_comments_to_insert), batch_size):
|
|
||||||
batch = status_comments_to_insert[i:i+batch_size]
|
|
||||||
cursor.executemany("""
|
|
||||||
INSERT INTO ecoFacilityStatus (facilityId, statusComment)
|
|
||||||
VALUES (?, ?)
|
|
||||||
""", batch)
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
log_message = f"Inserted comment batch {i//batch_size + 1}/{(len(status_comments_to_insert)-1)//batch_size + 1}"
|
|
||||||
print(log_message)
|
|
||||||
log_file.write(log_message + "\n")
|
|
||||||
|
|
||||||
# Get final counts
|
|
||||||
cursor.execute("SELECT COUNT(*) FROM ecoFacilities")
|
|
||||||
total_facilities = cursor.fetchone()[0]
|
|
||||||
|
|
||||||
cursor.execute("SELECT COUNT(*) FROM ecoFacilityStatus")
|
|
||||||
total_comments = cursor.fetchone()[0]
|
|
||||||
|
|
||||||
# Log completion
|
|
||||||
completion_message = f"\nGeneration complete at {datetime.now()}"
|
|
||||||
print(completion_message)
|
|
||||||
log_file.write(completion_message + "\n")
|
|
||||||
|
|
||||||
summary = f"Total facilities in database: {total_facilities}\n"
|
|
||||||
summary += f"Total status comments in database: {total_comments}\n"
|
|
||||||
summary += f"Generated facilities saved to generated_facilities.csv for reference"
|
|
||||||
|
|
||||||
print(summary)
|
|
||||||
log_file.write(summary)
|
|
||||||
|
|
||||||
# Close connections
|
|
||||||
log_file.close()
|
|
||||||
csv_file.close()
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
print("\nSuccessfully added 1000 new ecological facilities to the database.")
|
|
||||||
print("A detailed log and CSV export have been created for reference.")
|
|
@@ -1,79 +0,0 @@
|
|||||||
<?php
|
|
||||||
// Connect to the SQLite database
|
|
||||||
$db = new PDO('sqlite:Databases/ecobuddy.sqlite');
|
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
||||||
|
|
||||||
// List of real first names for usernames
|
|
||||||
$firstNames = [
|
|
||||||
'James', 'John', 'Robert', 'Michael', 'William', 'David', 'Richard', 'Joseph', 'Thomas', 'Charles',
|
|
||||||
'Christopher', 'Daniel', 'Matthew', 'Anthony', 'Mark', 'Donald', 'Steven', 'Paul', 'Andrew', 'Joshua',
|
|
||||||
'Kenneth', 'Kevin', 'Brian', 'George', 'Timothy', 'Ronald', 'Edward', 'Jason', 'Jeffrey', 'Ryan',
|
|
||||||
'Jacob', 'Gary', 'Nicholas', 'Eric', 'Jonathan', 'Stephen', 'Larry', 'Justin', 'Scott', 'Brandon',
|
|
||||||
'Benjamin', 'Samuel', 'Gregory', 'Alexander', 'Frank', 'Patrick', 'Raymond', 'Jack', 'Dennis', 'Jerry',
|
|
||||||
'Tyler', 'Aaron', 'Jose', 'Adam', 'Nathan', 'Henry', 'Douglas', 'Zachary', 'Peter', 'Kyle',
|
|
||||||
'Ethan', 'Walter', 'Noah', 'Jeremy', 'Christian', 'Keith', 'Roger', 'Terry', 'Gerald', 'Harold',
|
|
||||||
'Sean', 'Austin', 'Carl', 'Arthur', 'Lawrence', 'Dylan', 'Jesse', 'Jordan', 'Bryan', 'Billy',
|
|
||||||
'Joe', 'Bruce', 'Gabriel', 'Logan', 'Albert', 'Willie', 'Alan', 'Juan', 'Wayne', 'Elijah',
|
|
||||||
'Randy', 'Roy', 'Vincent', 'Ralph', 'Eugene', 'Russell', 'Bobby', 'Mason', 'Philip', 'Louis'
|
|
||||||
];
|
|
||||||
|
|
||||||
// List of common words for password generation
|
|
||||||
$words = [
|
|
||||||
'Apple', 'Banana', 'Cherry', 'Dragon', 'Eagle', 'Forest', 'Garden', 'Harbor', 'Island', 'Jungle',
|
|
||||||
'Kingdom', 'Lemon', 'Mountain', 'Nature', 'Ocean', 'Planet', 'Queen', 'River', 'Summer', 'Tiger',
|
|
||||||
'Universe', 'Volcano', 'Winter', 'Yellow', 'Zebra', 'Castle', 'Diamond', 'Emerald', 'Flower', 'Galaxy',
|
|
||||||
'Horizon', 'Iceberg', 'Journey', 'Knight', 'Legend', 'Meadow', 'Nebula', 'Oasis', 'Palace', 'Quasar',
|
|
||||||
'Rainbow', 'Sapphire', 'Thunder', 'Unicorn', 'Victory', 'Whisper', 'Xylophone', 'Yacht', 'Zephyr', 'Autumn',
|
|
||||||
'Breeze', 'Cascade', 'Dolphin', 'Eclipse', 'Falcon', 'Glacier', 'Harmony', 'Infinity', 'Jasmine', 'Kaleidoscope',
|
|
||||||
'Lighthouse', 'Mirage', 'Nightfall', 'Orchard', 'Phoenix', 'Quicksilver', 'Radiance', 'Serenity', 'Twilight', 'Umbrella'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Check if we already have users with these names
|
|
||||||
$existingUsers = [];
|
|
||||||
$stmt = $db->query("SELECT username FROM ecoUser");
|
|
||||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$existingUsers[] = $row['username'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare the SQL statement for inserting users
|
|
||||||
$insertStmt = $db->prepare("INSERT INTO ecoUser (username, password, userType) VALUES (?, ?, ?)");
|
|
||||||
|
|
||||||
// Create a file to store usernames and passwords
|
|
||||||
$file = fopen("user_credentials.txt", "w");
|
|
||||||
fwrite($file, "Username,Password\n");
|
|
||||||
|
|
||||||
// Generate 50 users
|
|
||||||
$usersAdded = 0;
|
|
||||||
$usedNames = [];
|
|
||||||
shuffle($firstNames);
|
|
||||||
|
|
||||||
foreach ($firstNames as $name) {
|
|
||||||
if ($usersAdded >= 50) break;
|
|
||||||
|
|
||||||
// Skip if the name is already in the database
|
|
||||||
if (in_array($name, $existingUsers) || in_array($name, $usedNames)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate password in format (Word)(Word)(Word)(Digit)
|
|
||||||
$password = $words[array_rand($words)] . $words[array_rand($words)] . $words[array_rand($words)] . rand(0, 9);
|
|
||||||
|
|
||||||
// Hash the password using SHA-256
|
|
||||||
$hashedPassword = hash('sha256', $password);
|
|
||||||
|
|
||||||
// Insert the user into the database (userType 2 is for standard users)
|
|
||||||
$insertStmt->execute([$name, $hashedPassword, 2]);
|
|
||||||
|
|
||||||
// Write the credentials to the file
|
|
||||||
fwrite($file, "$name,$password\n");
|
|
||||||
|
|
||||||
$usedNames[] = $name;
|
|
||||||
$usersAdded++;
|
|
||||||
|
|
||||||
echo "Added user: $name\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($file);
|
|
||||||
|
|
||||||
echo "\nSuccessfully added $usersAdded users to the database.\n";
|
|
||||||
echo "Usernames and passwords have been saved to user_credentials.txt\n";
|
|
@@ -1,79 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import random
|
|
||||||
import hashlib
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Connect to the SQLite database
|
|
||||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# List of real first names for usernames
|
|
||||||
first_names = [
|
|
||||||
'James', 'John', 'Robert', 'Michael', 'William', 'David', 'Richard', 'Joseph', 'Thomas', 'Charles',
|
|
||||||
'Christopher', 'Daniel', 'Matthew', 'Anthony', 'Mark', 'Donald', 'Steven', 'Paul', 'Andrew', 'Joshua',
|
|
||||||
'Kenneth', 'Kevin', 'Brian', 'George', 'Timothy', 'Ronald', 'Edward', 'Jason', 'Jeffrey', 'Ryan',
|
|
||||||
'Jacob', 'Gary', 'Nicholas', 'Eric', 'Jonathan', 'Stephen', 'Larry', 'Justin', 'Scott', 'Brandon',
|
|
||||||
'Benjamin', 'Samuel', 'Gregory', 'Alexander', 'Frank', 'Patrick', 'Raymond', 'Jack', 'Dennis', 'Jerry',
|
|
||||||
'Tyler', 'Aaron', 'Jose', 'Adam', 'Nathan', 'Henry', 'Douglas', 'Zachary', 'Peter', 'Kyle',
|
|
||||||
'Ethan', 'Walter', 'Noah', 'Jeremy', 'Christian', 'Keith', 'Roger', 'Terry', 'Gerald', 'Harold',
|
|
||||||
'Sean', 'Austin', 'Carl', 'Arthur', 'Lawrence', 'Dylan', 'Jesse', 'Jordan', 'Bryan', 'Billy',
|
|
||||||
'Joe', 'Bruce', 'Gabriel', 'Logan', 'Albert', 'Willie', 'Alan', 'Juan', 'Wayne', 'Elijah',
|
|
||||||
'Randy', 'Roy', 'Vincent', 'Ralph', 'Eugene', 'Russell', 'Bobby', 'Mason', 'Philip', 'Louis'
|
|
||||||
]
|
|
||||||
|
|
||||||
# List of common words for password generation
|
|
||||||
words = [
|
|
||||||
'Apple', 'Banana', 'Cherry', 'Dragon', 'Eagle', 'Forest', 'Garden', 'Harbor', 'Island', 'Jungle',
|
|
||||||
'Kingdom', 'Lemon', 'Mountain', 'Nature', 'Ocean', 'Planet', 'Queen', 'River', 'Summer', 'Tiger',
|
|
||||||
'Universe', 'Volcano', 'Winter', 'Yellow', 'Zebra', 'Castle', 'Diamond', 'Emerald', 'Flower', 'Galaxy',
|
|
||||||
'Horizon', 'Iceberg', 'Journey', 'Knight', 'Legend', 'Meadow', 'Nebula', 'Oasis', 'Palace', 'Quasar',
|
|
||||||
'Rainbow', 'Sapphire', 'Thunder', 'Unicorn', 'Victory', 'Whisper', 'Xylophone', 'Yacht', 'Zephyr', 'Autumn',
|
|
||||||
'Breeze', 'Cascade', 'Dolphin', 'Eclipse', 'Falcon', 'Glacier', 'Harmony', 'Infinity', 'Jasmine', 'Kaleidoscope',
|
|
||||||
'Lighthouse', 'Mirage', 'Nightfall', 'Orchard', 'Phoenix', 'Quicksilver', 'Radiance', 'Serenity', 'Twilight', 'Umbrella'
|
|
||||||
]
|
|
||||||
|
|
||||||
# Check if we already have users with these names
|
|
||||||
cursor.execute("SELECT username FROM ecoUser")
|
|
||||||
existing_users = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Create a file to store usernames and passwords
|
|
||||||
with open("user_credentials.txt", "w") as file:
|
|
||||||
file.write("Username,Password\n")
|
|
||||||
|
|
||||||
# Generate 50 users
|
|
||||||
users_added = 0
|
|
||||||
used_names = []
|
|
||||||
random.shuffle(first_names)
|
|
||||||
|
|
||||||
for name in first_names:
|
|
||||||
if users_added >= 50:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Skip if the name is already in the database
|
|
||||||
if name in existing_users or name in used_names:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Generate password in format (Word)(Word)(Word)(Digit)
|
|
||||||
password = random.choice(words) + random.choice(words) + random.choice(words) + str(random.randint(0, 9))
|
|
||||||
|
|
||||||
# Hash the password using SHA-256
|
|
||||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
|
||||||
|
|
||||||
# Insert the user into the database (userType 2 is for standard users)
|
|
||||||
cursor.execute("INSERT INTO ecoUser (username, password, userType) VALUES (?, ?, ?)",
|
|
||||||
(name, hashed_password, 2))
|
|
||||||
|
|
||||||
# Write the credentials to the file
|
|
||||||
file.write(f"{name},{password}\n")
|
|
||||||
|
|
||||||
used_names.append(name)
|
|
||||||
users_added += 1
|
|
||||||
|
|
||||||
print(f"Added user: {name}")
|
|
||||||
|
|
||||||
# Commit the changes and close the connection
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
print(f"\nSuccessfully added {users_added} users to the database.")
|
|
||||||
print("Usernames and passwords have been saved to user_credentials.txt")
|
|
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,9 @@
|
|||||||
require_once('UserDataSet.php');
|
require_once('UserDataSet.php');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authentication service for handling JWT-based authentication
|
* Backend Authentication service for handling JWT authentication
|
||||||
|
* https://jwt.io/introduction
|
||||||
|
* This cost me blood, sweat and tears, mostly tears.
|
||||||
*/
|
*/
|
||||||
class AuthService {
|
class AuthService {
|
||||||
private string $secretKey;
|
private string $secretKey;
|
||||||
@@ -14,7 +16,7 @@ class AuthService {
|
|||||||
* @throws Exception if OpenSSL extension is not loaded
|
* @throws Exception if OpenSSL extension is not loaded
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
// Load environment variables from .env file
|
// Load environment variables from .env file (:D more configuration needs to be added to .env, but scope creep already huge)
|
||||||
$envFile = __DIR__ . '/../.env';
|
$envFile = __DIR__ . '/../.env';
|
||||||
if (file_exists($envFile)) {
|
if (file_exists($envFile)) {
|
||||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
@@ -37,14 +39,14 @@ class AuthService {
|
|||||||
$this->secretKey = getenv('JWT_SECRET_KEY') ?: 'your-256-bit-secret';
|
$this->secretKey = getenv('JWT_SECRET_KEY') ?: 'your-256-bit-secret';
|
||||||
$this->tokenExpiry = (int)(getenv('JWT_TOKEN_EXPIRY') ?: 3600);
|
$this->tokenExpiry = (int)(getenv('JWT_TOKEN_EXPIRY') ?: 3600);
|
||||||
|
|
||||||
// Verify OpenSSL extension is available
|
// Verify OpenSSL extension is available. This should be on by default regardless, but just in case.
|
||||||
if (!extension_loaded('openssl')) {
|
if (!extension_loaded('openssl')) {
|
||||||
throw new Exception('OpenSSL extension is required for JWT');
|
throw new Exception('OpenSSL extension is required for JWT');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a JWT token for a user
|
* Generates a JWT token
|
||||||
* @param array $userData User information to include in token
|
* @param array $userData User information to include in token
|
||||||
* @return string The generated JWT token
|
* @return string The generated JWT token
|
||||||
*/
|
*/
|
||||||
@@ -52,6 +54,7 @@ class AuthService {
|
|||||||
$issuedAt = time();
|
$issuedAt = time();
|
||||||
$expire = $issuedAt + $this->tokenExpiry;
|
$expire = $issuedAt + $this->tokenExpiry;
|
||||||
|
|
||||||
|
// Create payload with user data
|
||||||
$payload = [
|
$payload = [
|
||||||
'iat' => $issuedAt,
|
'iat' => $issuedAt,
|
||||||
'exp' => $expire,
|
'exp' => $expire,
|
||||||
@@ -101,7 +104,7 @@ class AuthService {
|
|||||||
$signature = hash_hmac('sha256', "$header.$payload", $this->secretKey, true);
|
$signature = hash_hmac('sha256', "$header.$payload", $this->secretKey, true);
|
||||||
$signature = $this->base64UrlEncode($signature);
|
$signature = $this->base64UrlEncode($signature);
|
||||||
|
|
||||||
return "$header.$payload.$signature";
|
return "$header.$payload.$signature"; //Wooooooo!!! JWT is a thing!
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,15 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Represents a facility in the EcoBuddy system
|
* Represents a singular facility
|
||||||
*
|
*
|
||||||
* This class serves as a data model for facilities, encapsulating all
|
* Data model for facilities, encapsulating all
|
||||||
* the properties and behaviours of a single facility. It follows the
|
* properties and behaviours of a single facility.
|
||||||
* Data Transfer Object (DTO) pattern that I learned about in my
|
|
||||||
* software architecture module.
|
|
||||||
*
|
*
|
||||||
* Each facility has location data, descriptive information, and metadata
|
* Each facility has location data, descriptive info, and metadata.
|
||||||
* about who contributed it. This class provides a clean interface for
|
|
||||||
* accessing this data throughout the application.
|
|
||||||
*/
|
*/
|
||||||
class FacilityData {
|
class FacilityData {
|
||||||
/**
|
/**
|
||||||
@@ -77,10 +73,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's title
|
* Gets the facility's title
|
||||||
*
|
|
||||||
* The title is the primary name or label for the facility that
|
|
||||||
* is displayed to users in the interface.
|
|
||||||
*
|
|
||||||
* @return string The facility title
|
* @return string The facility title
|
||||||
*/
|
*/
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
@@ -89,10 +81,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's category
|
* Gets the facility's category
|
||||||
*
|
|
||||||
* The category helps classify facilities by type, such as
|
|
||||||
* recycling centre, community garden, etc.
|
|
||||||
*
|
|
||||||
* @return string The facility category
|
* @return string The facility category
|
||||||
*/
|
*/
|
||||||
public function getCategory() {
|
public function getCategory() {
|
||||||
@@ -101,10 +89,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's current status
|
* Gets the facility's current status
|
||||||
*
|
|
||||||
* The status indicates whether the facility is operational,
|
|
||||||
* under maintenance, closed, etc.
|
|
||||||
*
|
|
||||||
* @return string The facility status
|
* @return string The facility status
|
||||||
*/
|
*/
|
||||||
public function getStatus() {
|
public function getStatus() {
|
||||||
@@ -113,10 +97,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's description
|
* Gets the facility's description
|
||||||
*
|
|
||||||
* The description provides detailed information about the facility,
|
|
||||||
* its purpose, services offered, etc.
|
|
||||||
*
|
|
||||||
* @return string The facility description
|
* @return string The facility description
|
||||||
*/
|
*/
|
||||||
public function getDescription() {
|
public function getDescription() {
|
||||||
@@ -125,9 +105,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's house/building number
|
* Gets the facility's house/building number
|
||||||
*
|
|
||||||
* This is part of the facility's address and helps locate it physically.
|
|
||||||
*
|
|
||||||
* @return string The house/building number
|
* @return string The house/building number
|
||||||
*/
|
*/
|
||||||
public function getHouseNumber() {
|
public function getHouseNumber() {
|
||||||
@@ -136,9 +113,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's street name
|
* Gets the facility's street name
|
||||||
*
|
|
||||||
* This is part of the facility's address and helps locate it physically.
|
|
||||||
*
|
|
||||||
* @return string The street name
|
* @return string The street name
|
||||||
*/
|
*/
|
||||||
public function getStreetName() {
|
public function getStreetName() {
|
||||||
@@ -147,9 +121,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's county
|
* Gets the facility's county
|
||||||
*
|
|
||||||
* This is part of the facility's address and helps locate it physically.
|
|
||||||
*
|
|
||||||
* @return string The county
|
* @return string The county
|
||||||
*/
|
*/
|
||||||
public function getCounty() {
|
public function getCounty() {
|
||||||
@@ -158,9 +129,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's town or city
|
* Gets the facility's town or city
|
||||||
*
|
|
||||||
* This is part of the facility's address and helps locate it physically.
|
|
||||||
*
|
|
||||||
* @return string The town or city
|
* @return string The town or city
|
||||||
*/
|
*/
|
||||||
public function getTown() {
|
public function getTown() {
|
||||||
@@ -169,10 +137,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's postcode
|
* Gets the facility's postcode
|
||||||
*
|
|
||||||
* This is part of the facility's address and helps locate it physically.
|
|
||||||
* It's also useful for searching facilities by location.
|
|
||||||
*
|
|
||||||
* @return string The postcode
|
* @return string The postcode
|
||||||
*/
|
*/
|
||||||
public function getPostcode() {
|
public function getPostcode() {
|
||||||
@@ -181,10 +145,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's longitude coordinate
|
* Gets the facility's longitude coordinate
|
||||||
*
|
|
||||||
* This is used for displaying the facility on a map and
|
|
||||||
* for calculating distances between facilities.
|
|
||||||
*
|
|
||||||
* @return float The longitude coordinate
|
* @return float The longitude coordinate
|
||||||
*/
|
*/
|
||||||
public function getLng() {
|
public function getLng() {
|
||||||
@@ -193,10 +153,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facility's latitude coordinate
|
* Gets the facility's latitude coordinate
|
||||||
*
|
|
||||||
* This is used for displaying the facility on a map and
|
|
||||||
* for calculating distances between facilities.
|
|
||||||
*
|
|
||||||
* @return float The latitude coordinate
|
* @return float The latitude coordinate
|
||||||
*/
|
*/
|
||||||
public function getLat() {
|
public function getLat() {
|
||||||
@@ -205,10 +161,6 @@ class FacilityData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the username of the facility's contributor
|
* Gets the username of the facility's contributor
|
||||||
*
|
|
||||||
* This tracks who added the facility to the system,
|
|
||||||
* which is useful for auditing and attribution.
|
|
||||||
*
|
|
||||||
* @return string The contributor's username
|
* @return string The contributor's username
|
||||||
*/
|
*/
|
||||||
public function getContributor() {
|
public function getContributor() {
|
||||||
|
@@ -1,57 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once('FacilityDataSet.php');
|
|
||||||
class Paginator {
|
|
||||||
protected $_pages, $_totalPages, $_rowLimit, $_pageMatrix, $_rowCount;
|
|
||||||
|
|
||||||
public function __construct($rowLimit, $dataset) {
|
|
||||||
$this->_rowLimit = $rowLimit;
|
|
||||||
$this->_totalPages = $this->calculateTotalPages($dataset['count']);
|
|
||||||
$this->_rowCount = $dataset['count'];
|
|
||||||
$this->_pages = $dataset['dataset'];
|
|
||||||
$this->_pageMatrix = $this->Paginate();
|
|
||||||
}
|
|
||||||
public function getTotalPages() {
|
|
||||||
return $this->_totalPages;
|
|
||||||
}
|
|
||||||
private function calculateTotalPages(int $count): int {
|
|
||||||
return $count > 0 ? ceil($count / $this->_rowLimit) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function Paginate(): array {
|
|
||||||
$pageMatrix = [];
|
|
||||||
for ($i = 0; $i < $this->_totalPages; $i++) {
|
|
||||||
$page = [];
|
|
||||||
$start = $i * $this->_rowLimit;
|
|
||||||
$end = min($start + $this->_rowLimit, $this->_rowCount); // Ensure within bounds
|
|
||||||
|
|
||||||
for ($j = $start; $j < $end; $j++) {
|
|
||||||
$page[] = $this->_pages[$j];
|
|
||||||
}
|
|
||||||
|
|
||||||
$pageMatrix[$i] = $page;
|
|
||||||
}
|
|
||||||
return $pageMatrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPageFromUri(): int {
|
|
||||||
// Retrieve 'page' parameter and default to 0 if missing or invalid
|
|
||||||
return filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, [
|
|
||||||
'options' => ['default' => 0, 'min_range' => 0] // Default to 1 if invalid or missing
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPage(int $pageNumber): array {
|
|
||||||
|
|
||||||
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
|
|
||||||
return []; // Return an empty array if the page number is invalid
|
|
||||||
}
|
|
||||||
return $this->_pageMatrix[$pageNumber];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function countPageResults(int $pageNumber): int {
|
|
||||||
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
|
|
||||||
return 0; // Return 0 if the page number is invalid
|
|
||||||
}
|
|
||||||
return count($this->_pageMatrix[$pageNumber]);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -70,16 +70,6 @@ class User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the user's access level
|
|
||||||
*
|
|
||||||
* @param int $level The access level to set (admin = 1, regular user = 2)
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function setAccessLevel($level) {
|
|
||||||
$this->_accessLevel = $level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the user's access level
|
* Gets the user's access level
|
||||||
*
|
*
|
||||||
@@ -129,33 +119,6 @@ class User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the user out
|
|
||||||
*
|
|
||||||
* Resets all user properties to their default values.
|
|
||||||
* Note: This doesn't invalidate the JWT token - handled client-side
|
|
||||||
* by removing the token from storage.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function logout() {
|
|
||||||
// Reset user properties
|
|
||||||
$this->_loggedIn = false;
|
|
||||||
$this->_username = "None";
|
|
||||||
$this->_userId = "0";
|
|
||||||
$this->_accessLevel = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user is currently logged in
|
|
||||||
*
|
|
||||||
* @return bool True if the user is logged in, false otherwise
|
|
||||||
*/
|
|
||||||
public function isLoggedIn(): bool
|
|
||||||
{
|
|
||||||
return $this->_loggedIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static method to check if a request is authenticated
|
* Static method to check if a request is authenticated
|
||||||
*
|
*
|
||||||
|
@@ -112,7 +112,7 @@
|
|||||||
<input type="text" class="form-control" id="postcode" name="postcode"
|
<input type="text" class="form-control" id="postcode" name="postcode"
|
||||||
placeholder="e.g. M1 5GD" required>
|
placeholder="e.g. M1 5GD" required>
|
||||||
<button class="btn btn-success" type="submit">
|
<button class="btn btn-success" type="submit">
|
||||||
<i class="bi bi-search me-1"></i>Search
|
<i class="bi bi-crosshair"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,7 +151,8 @@
|
|||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<i class="bi bi-geo-alt text-success" style="font-size: 3rem;"></i>
|
<i class="bi bi-geo-alt text-success" style="font-size: 3rem;"></i>
|
||||||
<h4 class="mt-3">Enter a Postcode</h4>
|
<h4 class="mt-3">Enter a Postcode</h4>
|
||||||
<p class="text-muted">Please enter a postcode to view facilities on the map</p>
|
<p class="text-muted mb-0">Please enter a postcode to view facilities on the map</p>
|
||||||
|
<p class="text-muted mt-0">or use the search button to find facilities near you</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -159,11 +159,6 @@
|
|||||||
<i class="bi bi-map-fill me-1"></i>Map
|
<i class="bi bi-map-fill me-1"></i>Map
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/about.php">
|
|
||||||
<i class="bi bi-info-circle-fill me-1"></i>About
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,225 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import random
|
|
||||||
|
|
||||||
# Connect to the SQLite database
|
|
||||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# Check if we need to add any new categories
|
|
||||||
cursor.execute("SELECT id FROM ecoCategories")
|
|
||||||
existing_categories = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Add two new categories
|
|
||||||
new_categories = [
|
|
||||||
(16, "Urban Farms"),
|
|
||||||
(17, "Rainwater Harvesting Systems")
|
|
||||||
]
|
|
||||||
|
|
||||||
for category in new_categories:
|
|
||||||
if category[0] not in existing_categories:
|
|
||||||
cursor.execute("INSERT INTO ecoCategories (id, name) VALUES (?, ?)", category)
|
|
||||||
print(f"Added new category: {category[1]}")
|
|
||||||
|
|
||||||
# Get list of user IDs for contributors
|
|
||||||
cursor.execute("SELECT id FROM ecoUser")
|
|
||||||
user_ids = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Define 10 new ecological facilities in the UK with accurate location data
|
|
||||||
new_facilities = [
|
|
||||||
{
|
|
||||||
"title": "Community Garden Hackney",
|
|
||||||
"category": 12, # Pollinator Gardens
|
|
||||||
"description": "Urban garden with native plants to support local pollinators",
|
|
||||||
"houseNumber": "45",
|
|
||||||
"streetName": "Dalston Lane",
|
|
||||||
"county": "Greater London",
|
|
||||||
"town": "London",
|
|
||||||
"postcode": "E8 3AH",
|
|
||||||
"lng": -0.0612,
|
|
||||||
"lat": 51.5476,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Recently expanded with new wildflower section",
|
|
||||||
"Volunteer days every Saturday"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Rooftop Solar Farm",
|
|
||||||
"category": 8, # Green Roofs
|
|
||||||
"description": "Combined green roof and solar panel installation on commercial building",
|
|
||||||
"houseNumber": "120",
|
|
||||||
"streetName": "Deansgate",
|
|
||||||
"county": "Greater Manchester",
|
|
||||||
"town": "Manchester",
|
|
||||||
"postcode": "M3 2QJ",
|
|
||||||
"lng": -2.2484,
|
|
||||||
"lat": 53.4808,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Generates power for the entire building"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Edinburgh Tool Library",
|
|
||||||
"category": 15, # Community Tool Libraries
|
|
||||||
"description": "Borrow tools instead of buying them - reducing waste and consumption",
|
|
||||||
"houseNumber": "25",
|
|
||||||
"streetName": "Leith Walk",
|
|
||||||
"county": "Edinburgh",
|
|
||||||
"town": "Edinburgh",
|
|
||||||
"postcode": "EH6 8LN",
|
|
||||||
"lng": -3.1752,
|
|
||||||
"lat": 55.9677,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Cardiff Bay Water Refill Station",
|
|
||||||
"category": 9, # Public Water Refill Stations
|
|
||||||
"description": "Free water refill station to reduce plastic bottle usage",
|
|
||||||
"houseNumber": "3",
|
|
||||||
"streetName": "Mermaid Quay",
|
|
||||||
"county": "Cardiff",
|
|
||||||
"town": "Cardiff",
|
|
||||||
"postcode": "CF10 5BZ",
|
|
||||||
"lng": -3.1644,
|
|
||||||
"lat": 51.4644,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Recently cleaned and maintained",
|
|
||||||
"High usage during summer months"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Bristol Urban Farm",
|
|
||||||
"category": 16, # Urban Farms (new category)
|
|
||||||
"description": "Community-run urban farm providing local produce and education",
|
|
||||||
"houseNumber": "18",
|
|
||||||
"streetName": "Stapleton Road",
|
|
||||||
"county": "Bristol",
|
|
||||||
"town": "Bristol",
|
|
||||||
"postcode": "BS5 0RA",
|
|
||||||
"lng": -2.5677,
|
|
||||||
"lat": 51.4635,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Open for volunteers Tuesday-Sunday"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Newcastle Rainwater Collection System",
|
|
||||||
"category": 17, # Rainwater Harvesting Systems (new category)
|
|
||||||
"description": "Public demonstration of rainwater harvesting for garden irrigation",
|
|
||||||
"houseNumber": "55",
|
|
||||||
"streetName": "Northumberland Street",
|
|
||||||
"county": "Tyne and Wear",
|
|
||||||
"town": "Newcastle upon Tyne",
|
|
||||||
"postcode": "NE1 7DH",
|
|
||||||
"lng": -1.6178,
|
|
||||||
"lat": 54.9783,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Brighton Beach Solar Bench",
|
|
||||||
"category": 7, # Solar-Powered Benches
|
|
||||||
"description": "Solar-powered bench with USB charging ports and WiFi",
|
|
||||||
"houseNumber": "",
|
|
||||||
"streetName": "Kings Road",
|
|
||||||
"county": "East Sussex",
|
|
||||||
"town": "Brighton",
|
|
||||||
"postcode": "BN1 2FN",
|
|
||||||
"lng": -0.1426,
|
|
||||||
"lat": 50.8214,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Popular spot for tourists",
|
|
||||||
"One USB port currently not working"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Leeds Community Compost Hub",
|
|
||||||
"category": 6, # Community Compost Bins
|
|
||||||
"description": "Large-scale community composting facility for local residents",
|
|
||||||
"houseNumber": "78",
|
|
||||||
"streetName": "Woodhouse Lane",
|
|
||||||
"county": "West Yorkshire",
|
|
||||||
"town": "Leeds",
|
|
||||||
"postcode": "LS2 9JT",
|
|
||||||
"lng": -1.5491,
|
|
||||||
"lat": 53.8067,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"Recently expanded capacity"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Glasgow EV Charging Hub",
|
|
||||||
"category": 4, # Public EV Charging Stations
|
|
||||||
"description": "Multi-vehicle EV charging station with fast chargers",
|
|
||||||
"houseNumber": "42",
|
|
||||||
"streetName": "Buchanan Street",
|
|
||||||
"county": "Glasgow",
|
|
||||||
"town": "Glasgow",
|
|
||||||
"postcode": "G1 3JX",
|
|
||||||
"lng": -4.2526,
|
|
||||||
"lat": 55.8621,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": [
|
|
||||||
"6 charging points available",
|
|
||||||
"24/7 access"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Oxford E-Waste Collection Center",
|
|
||||||
"category": 13, # E-Waste Collection Bins
|
|
||||||
"description": "Dedicated facility for proper disposal and recycling of electronic waste",
|
|
||||||
"houseNumber": "15",
|
|
||||||
"streetName": "St Aldate's",
|
|
||||||
"county": "Oxfordshire",
|
|
||||||
"town": "Oxford",
|
|
||||||
"postcode": "OX1 1BX",
|
|
||||||
"lng": -1.2577,
|
|
||||||
"lat": 51.7520,
|
|
||||||
"contributor": random.choice(user_ids),
|
|
||||||
"status_comments": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# Insert facilities into the database
|
|
||||||
for facility in new_facilities:
|
|
||||||
cursor.execute("""
|
|
||||||
INSERT INTO ecoFacilities
|
|
||||||
(title, category, description, houseNumber, streetName, county, town, postcode, lng, lat, contributor)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
""", (
|
|
||||||
facility["title"],
|
|
||||||
facility["category"],
|
|
||||||
facility["description"],
|
|
||||||
facility["houseNumber"],
|
|
||||||
facility["streetName"],
|
|
||||||
facility["county"],
|
|
||||||
facility["town"],
|
|
||||||
facility["postcode"],
|
|
||||||
facility["lng"],
|
|
||||||
facility["lat"],
|
|
||||||
facility["contributor"]
|
|
||||||
))
|
|
||||||
|
|
||||||
# Get the ID of the inserted facility
|
|
||||||
facility_id = cursor.lastrowid
|
|
||||||
|
|
||||||
# Add status comments if any
|
|
||||||
for comment in facility["status_comments"]:
|
|
||||||
cursor.execute("""
|
|
||||||
INSERT INTO ecoFacilityStatus (facilityId, statusComment)
|
|
||||||
VALUES (?, ?)
|
|
||||||
""", (facility_id, comment))
|
|
||||||
|
|
||||||
print(f"Added facility: {facility['title']} in {facility['town']}")
|
|
||||||
|
|
||||||
# Commit the changes and close the connection
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
print("\nSuccessfully added 10 new ecological facilities to the database.")
|
|
@@ -7,8 +7,7 @@
|
|||||||
* The client uses JWT tokens for authentication, which are automatically
|
* The client uses JWT tokens for authentication, which are automatically
|
||||||
* included in requests via the fetchAuth function provided by the simpleAuth service.
|
* included in requests via the fetchAuth function provided by the simpleAuth service.
|
||||||
*
|
*
|
||||||
* NOTE: For authentication (login, logout, token validation), please use the simpleAuth
|
* Similar to AuthService.php, great pain and countless tears. And learning woooo!!!!!!!!
|
||||||
* service directly instead of this API client.
|
|
||||||
*/
|
*/
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
/**
|
/**
|
||||||
|
@@ -28,6 +28,63 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
// Get facilities data from sessionStorage
|
// Get facilities data from sessionStorage
|
||||||
facilities = JSON.parse(sessionStorage.getItem('facilityData') || '[]');
|
facilities = JSON.parse(sessionStorage.getItem('facilityData') || '[]');
|
||||||
|
|
||||||
|
// Add location found handler
|
||||||
|
map.on('locationfound', function(e) {
|
||||||
|
try {
|
||||||
|
const { lat, lng } = e.latlng;
|
||||||
|
|
||||||
|
// Update the map directly with the coordinates
|
||||||
|
updateMapLocation({ lat, lng }, currentRadius);
|
||||||
|
|
||||||
|
// Remove overlay once we have a valid location
|
||||||
|
const overlay = document.getElementById('mapOverlay');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get postcode from coordinates
|
||||||
|
fetch(`https://api.postcodes.io/postcodes?lon=${lng}&lat=${lat}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 200 && data.result && data.result.length > 0) {
|
||||||
|
const postcode = data.result[0].postcode;
|
||||||
|
const postcodeInput = document.getElementById('postcode');
|
||||||
|
if (postcodeInput) {
|
||||||
|
postcodeInput.value = postcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error getting postcode:', error);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error processing location:', error);
|
||||||
|
alert('Error getting your location: ' + error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add location error handler
|
||||||
|
map.on('locationerror', function(e) {
|
||||||
|
console.error('Geolocation error:', e);
|
||||||
|
let message = 'Error getting your location: ';
|
||||||
|
|
||||||
|
switch(e.code) {
|
||||||
|
case 1: // PERMISSION_DENIED
|
||||||
|
message += 'Please enable location access in your browser settings.';
|
||||||
|
break;
|
||||||
|
case 2: // POSITION_UNAVAILABLE
|
||||||
|
message += 'Location information is unavailable.';
|
||||||
|
break;
|
||||||
|
case 3: // TIMEOUT
|
||||||
|
message += 'Location request timed out.';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message += 'An unknown error occurred.';
|
||||||
|
}
|
||||||
|
|
||||||
|
alert(message);
|
||||||
|
});
|
||||||
|
|
||||||
// Set up form handlers
|
// Set up form handlers
|
||||||
setupFormHandlers();
|
setupFormHandlers();
|
||||||
|
|
||||||
@@ -35,6 +92,84 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
setupHeaderSearchHandler();
|
setupHeaderSearchHandler();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get postcode from coordinates using postcodes.io API
|
||||||
|
* @param {number} lat - Latitude
|
||||||
|
* @param {number} lng - Longitude
|
||||||
|
* @returns {Promise<string>} The postcode
|
||||||
|
*/
|
||||||
|
async function getPostcodeFromCoordinates(lat, lng) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`https://api.postcodes.io/postcodes?lon=${lng}&lat=${lat}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Could not find postcode for coordinates');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.status === 200 && data.result && data.result.length > 0) {
|
||||||
|
return data.result[0].postcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('No postcode found for coordinates');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting postcode from coordinates:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle geolocation success
|
||||||
|
* @param {GeolocationPosition} position - The position object
|
||||||
|
*/
|
||||||
|
async function handleGeolocationSuccess(position) {
|
||||||
|
try {
|
||||||
|
const { latitude, longitude } = position.coords;
|
||||||
|
|
||||||
|
// Get postcode from coordinates
|
||||||
|
const postcode = await getPostcodeFromCoordinates(latitude, longitude);
|
||||||
|
|
||||||
|
// Update the postcode input
|
||||||
|
const postcodeInput = document.getElementById('postcode');
|
||||||
|
if (postcodeInput) {
|
||||||
|
postcodeInput.value = postcode;
|
||||||
|
|
||||||
|
// Submit the form to update the map
|
||||||
|
const postcodeForm = document.getElementById('postcodeForm');
|
||||||
|
if (postcodeForm) {
|
||||||
|
postcodeForm.dispatchEvent(new Event('submit'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error processing geolocation:', error);
|
||||||
|
alert('Error getting your location: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle geolocation error
|
||||||
|
* @param {GeolocationPositionError} error - The error object
|
||||||
|
*/
|
||||||
|
function handleGeolocationError(error) {
|
||||||
|
console.error('Geolocation error:', error);
|
||||||
|
let message = 'Error getting your location: ';
|
||||||
|
|
||||||
|
switch(error.code) {
|
||||||
|
case error.PERMISSION_DENIED:
|
||||||
|
message += 'Please enable location access in your browser settings.';
|
||||||
|
break;
|
||||||
|
case error.POSITION_UNAVAILABLE:
|
||||||
|
message += 'Location information is unavailable.';
|
||||||
|
break;
|
||||||
|
case error.TIMEOUT:
|
||||||
|
message += 'Location request timed out.';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message += 'An unknown error occurred.';
|
||||||
|
}
|
||||||
|
|
||||||
|
alert(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up form handlers for postcode and radius inputs
|
* Set up form handlers for postcode and radius inputs
|
||||||
*/
|
*/
|
||||||
@@ -43,6 +178,24 @@ function setupFormHandlers() {
|
|||||||
const radiusSelect = document.getElementById('radius');
|
const radiusSelect = document.getElementById('radius');
|
||||||
|
|
||||||
if (postcodeForm) {
|
if (postcodeForm) {
|
||||||
|
// Add geolocation functionality to the search button
|
||||||
|
const searchButton = postcodeForm.querySelector('button[type="submit"]');
|
||||||
|
if (searchButton) {
|
||||||
|
searchButton.onclick = (e) => {
|
||||||
|
// If the postcode input is empty, use geolocation
|
||||||
|
const postcodeInput = document.getElementById('postcode');
|
||||||
|
if (!postcodeInput.value.trim()) {
|
||||||
|
e.preventDefault();
|
||||||
|
map.locate({
|
||||||
|
setView: false,
|
||||||
|
enableHighAccuracy: true,
|
||||||
|
timeout: 10000,
|
||||||
|
maximumAge: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
postcodeForm.addEventListener('submit', async function(e) {
|
postcodeForm.addEventListener('submit', async function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -51,12 +204,7 @@ function setupFormHandlers() {
|
|||||||
|
|
||||||
// Show loading state
|
// Show loading state
|
||||||
const submitButton = this.querySelector('button[type="submit"]');
|
const submitButton = this.querySelector('button[type="submit"]');
|
||||||
const originalButtonContent = `<i class="bi bi-search me-1"></i>Search...`;
|
|
||||||
submitButton.disabled = true;
|
submitButton.disabled = true;
|
||||||
submitButton.innerHTML = `
|
|
||||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
|
||||||
<span class="ms-2">Searching...</span>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Validate postcode format first
|
// Validate postcode format first
|
||||||
if (!isValidPostcode(postcode)) {
|
if (!isValidPostcode(postcode)) {
|
||||||
@@ -92,7 +240,6 @@ function setupFormHandlers() {
|
|||||||
} finally {
|
} finally {
|
||||||
// Always reset button state
|
// Always reset button state
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
submitButton.innerHTML = originalButtonContent;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
console.log('Testing admin check:'); console.log('User with accessLevel 1:', simpleAuth.isAdmin.call({isAuthenticated: () => true, user: {accessLevel: 1}})); console.log('User with accessLevel 0:', simpleAuth.isAdmin.call({isAuthenticated: () => true, user: {accessLevel: 0}}));
|
|
Reference in New Issue
Block a user