@@ -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');
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
private string $secretKey;
|
||||
@@ -14,7 +16,7 @@ class AuthService {
|
||||
* @throws Exception if OpenSSL extension is not loaded
|
||||
*/
|
||||
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';
|
||||
if (file_exists($envFile)) {
|
||||
$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->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')) {
|
||||
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
|
||||
* @return string The generated JWT token
|
||||
*/
|
||||
@@ -52,6 +54,7 @@ class AuthService {
|
||||
$issuedAt = time();
|
||||
$expire = $issuedAt + $this->tokenExpiry;
|
||||
|
||||
// Create payload with user data
|
||||
$payload = [
|
||||
'iat' => $issuedAt,
|
||||
'exp' => $expire,
|
||||
@@ -101,7 +104,7 @@ class AuthService {
|
||||
$signature = hash_hmac('sha256', "$header.$payload", $this->secretKey, true);
|
||||
$signature = $this->base64UrlEncode($signature);
|
||||
|
||||
return "$header.$payload.$signature";
|
||||
return "$header.$payload.$signature"; //Wooooooo!!! JWT is a thing!
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,15 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* Represents a facility in the EcoBuddy system
|
||||
* Represents a singular facility
|
||||
*
|
||||
* This class serves as a data model for facilities, encapsulating all
|
||||
* the properties and behaviours of a single facility. It follows the
|
||||
* Data Transfer Object (DTO) pattern that I learned about in my
|
||||
* software architecture module.
|
||||
* Data model for facilities, encapsulating all
|
||||
* properties and behaviours of a single facility.
|
||||
*
|
||||
* Each facility has location data, descriptive information, and metadata
|
||||
* about who contributed it. This class provides a clean interface for
|
||||
* accessing this data throughout the application.
|
||||
* Each facility has location data, descriptive info, and metadata.
|
||||
*/
|
||||
class FacilityData {
|
||||
/**
|
||||
@@ -77,10 +73,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getTitle() {
|
||||
@@ -89,10 +81,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* Gets the facility's category
|
||||
*
|
||||
* The category helps classify facilities by type, such as
|
||||
* recycling centre, community garden, etc.
|
||||
*
|
||||
* @return string The facility category
|
||||
*/
|
||||
public function getCategory() {
|
||||
@@ -101,10 +89,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* Gets the facility's current status
|
||||
*
|
||||
* The status indicates whether the facility is operational,
|
||||
* under maintenance, closed, etc.
|
||||
*
|
||||
* @return string The facility status
|
||||
*/
|
||||
public function getStatus() {
|
||||
@@ -113,10 +97,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* Gets the facility's description
|
||||
*
|
||||
* The description provides detailed information about the facility,
|
||||
* its purpose, services offered, etc.
|
||||
*
|
||||
* @return string The facility description
|
||||
*/
|
||||
public function getDescription() {
|
||||
@@ -125,9 +105,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getHouseNumber() {
|
||||
@@ -136,9 +113,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* Gets the facility's street name
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
*
|
||||
* @return string The street name
|
||||
*/
|
||||
public function getStreetName() {
|
||||
@@ -147,9 +121,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* Gets the facility's county
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
*
|
||||
* @return string The county
|
||||
*/
|
||||
public function getCounty() {
|
||||
@@ -158,9 +129,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getTown() {
|
||||
@@ -169,10 +137,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getPostcode() {
|
||||
@@ -181,10 +145,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getLng() {
|
||||
@@ -193,10 +153,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getLat() {
|
||||
@@ -205,10 +161,6 @@ class FacilityData {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -128,33 +118,6 @@ class User {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@@ -112,7 +112,7 @@
|
||||
<input type="text" class="form-control" id="postcode" name="postcode"
|
||||
placeholder="e.g. M1 5GD" required>
|
||||
<button class="btn btn-success" type="submit">
|
||||
<i class="bi bi-search me-1"></i>Search
|
||||
<i class="bi bi-crosshair"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -151,7 +151,8 @@
|
||||
<div class="text-center">
|
||||
<i class="bi bi-geo-alt text-success" style="font-size: 3rem;"></i>
|
||||
<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>
|
||||
|
@@ -159,11 +159,6 @@
|
||||
<i class="bi bi-map-fill me-1"></i>Map
|
||||
</a>
|
||||
</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>
|
||||
|
||||
|
||||
|
@@ -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.")
|
@@ -6,9 +6,8 @@
|
||||
*
|
||||
* The client uses JWT tokens for authentication, which are automatically
|
||||
* included in requests via the fetchAuth function provided by the simpleAuth service.
|
||||
*
|
||||
* NOTE: For authentication (login, logout, token validation), please use the simpleAuth
|
||||
* service directly instead of this API client.
|
||||
*
|
||||
* Similar to AuthService.php, great pain and countless tears. And learning woooo!!!!!!!!
|
||||
*/
|
||||
class ApiClient {
|
||||
/**
|
||||
|
@@ -28,6 +28,63 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get facilities data from sessionStorage
|
||||
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
|
||||
setupFormHandlers();
|
||||
|
||||
@@ -35,6 +92,84 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
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
|
||||
*/
|
||||
@@ -43,6 +178,24 @@ function setupFormHandlers() {
|
||||
const radiusSelect = document.getElementById('radius');
|
||||
|
||||
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) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -51,12 +204,7 @@ function setupFormHandlers() {
|
||||
|
||||
// Show loading state
|
||||
const submitButton = this.querySelector('button[type="submit"]');
|
||||
const originalButtonContent = `<i class="bi bi-search me-1"></i>Search...`;
|
||||
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
|
||||
if (!isValidPostcode(postcode)) {
|
||||
@@ -92,7 +240,6 @@ function setupFormHandlers() {
|
||||
} finally {
|
||||
// Always reset button state
|
||||
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