Changeset 53bad7e


Ignore:
Timestamp:
01/10/25 00:33:50 (5 days ago)
Author:
Kristijan <kristijanzafirovski26@…>
Branches:
master
Children:
1c51912
Parents:
c164f8f
Message:

dodadeno informacii za broj na lugje

Files:
19 edited

Legend:

Unmodified
Added
Removed
  • backend/GlobeGuru-backend/src/main/java/AccountHandler.java

    rc164f8f r53bad7e  
    1616
    1717public class AccountHandler implements HttpHandler {
    18 
    19     // Simple in-memory session management
    2018    private static final Map<String, String> sessions = new ConcurrentHashMap<>();
    2119    private static final String CLIENT_ID = "376204422797-s8f05nn6drmec1cko2h4kg1nk24abgc9.apps.googleusercontent.com";
  • backend/GlobeGuru-backend/src/main/java/DatabaseUtil.java

    rc164f8f r53bad7e  
    3131                             "price REAL, " +
    3232                             "dateRange TEXT, " +
     33                             "numberOfPeople INTEGER, " +
    3334                             "isPriceChanged BOOLEAN DEFAULT 0, " +
    3435                             "newPrice REAL DEFAULT 0)"
     
    5556            stmt.setString(1, username);
    5657            stmt.setString(2, email);
    57             stmt.setString(3, password); // Store hashed
     58            stmt.setString(3, password);
    5859            return stmt.executeUpdate() > 0;
    5960        }
     
    6970                    String storedPassword = rs.getString("password");
    7071                    if (password == null) {
    71                         // Assume this is a Google login
     72                        // Google login
    7273                        return storedPassword == null;
    7374                    }
    74                     return password.equals(storedPassword); // Check hashed password
     75                    return password.equals(storedPassword);
    7576                }
    7677            }
     
    9293            try (ResultSet rs = selectStmt.executeQuery()) {
    9394                if (rs.next()) {
    94                     // User exists, delete the user and their favourite options
    9595                    deleteStmt.setInt(1, userId);
    9696                    int rowsAffected = deleteStmt.executeUpdate();
     
    101101                    return rowsAffected > 0;
    102102                } else {
    103                     // User does not exist
    104103                    return false;
    105104                }
     
    135134    }
    136135
    137     public static List<Option> queryOptions(String destination, String dateQuery, boolean dateFlag) throws SQLException {
     136    public static List<Option> queryOptions(String destination, String dateQuery, int numPeople, boolean dateFlag) throws SQLException {
    138137        List<Option> options = new ArrayList<>();
    139138        String sql = "SELECT * FROM options WHERE (country LIKE ? OR hotelName LIKE ?)";
     
    143142        } //append date
    144143        if (dateFlag) {   //search only from dates
    145             sql += "AND dateRange LIKE ?";
    146         }
     144            sql += " AND dateRange LIKE ?";
     145        }
     146        if(numPeople != 0) { //with number of people
     147            sql += " AND numberOfPeople = ?";
     148        }
     149
    147150        System.out.println("Searching for dest:" + destination + "\n" + sql);
    148151        try (Connection conn = getConnection();
     
    156159                stmt.setString(3, dateQuery + "%");
    157160            }
    158             // Execute query
     161            if(numPeople != 0) {
     162                stmt.setInt(4, numPeople);
     163            }
    159164            try (ResultSet rs = stmt.executeQuery()) {
    160165                while (rs.next()) {
     
    167172                    option.setPrice(rs.getFloat("price"));
    168173                    option.setDateRange(rs.getString("dateRange"));
     174                    option.setNumPeople(rs.getInt("numberOfPeople"));
    169175                    options.add(option);
    170176                }
     
    185191    }
    186192
    187     //TODO add frontend
     193
    188194    public static boolean removeFavoriteOption(int userId, int optionId) throws SQLException {
    189195        String sql = "DELETE FROM savedOptions WHERE userId = ? AND optionId = ?";
     
    269275
    270276    public static void saveOptionToDatabase(Option option) {
    271         String sql = "INSERT INTO options (link, imgSrc, hotelName, country, price, dateRange, isPriceChanged, newPrice) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
     277        String sql = "INSERT INTO options (link, imgSrc, hotelName, country, price, dateRange,numberOfPeople, isPriceChanged, newPrice) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
    272278        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:globe_guru.db");
    273279             PreparedStatement stmt = conn.prepareStatement(sql)) {
     
    278284            stmt.setFloat(5, option.getPrice());
    279285            stmt.setString(6, option.getDateRange());
    280             stmt.setBoolean(7, option.isPriceChanged());
    281             stmt.setFloat(8, option.getNewPrice());
     286            stmt.setInt(7,option.getNumPeople());
     287            stmt.setBoolean(8, option.isPriceChanged());
     288            stmt.setFloat(9, option.getNewPrice());
    282289            stmt.executeUpdate();
    283290        } catch (SQLException e) {
     
    293300            PreparedStatement stmt = conn.prepareStatement(sql)){
    294301            stmt.executeUpdate();
    295             //Remake the options DB
    296302            initializeDatabase();
    297303
     
    334340                    existingOption.setPriceChanged(rs.getBoolean("isPriceChanged"));
    335341                    existingOption.setNewPrice(rs.getInt("newPrice"));
     342                    existingOption.setNumPeople(rs.getInt("numberOfPeople"));
    336343                    return existingOption;
    337344                }
  • backend/GlobeGuru-backend/src/main/java/FrontendHandler.java

    rc164f8f r53bad7e  
    101101        String departureDate = formData.get("departureDate");
    102102        String nightsNumberStr = formData.get("nightsNumber");
     103        String numPeopleStr = formData.get("numberPeople");
    103104        int numberOfNights = (nightsNumberStr != null && !nightsNumberStr.isEmpty()) ? Integer.parseInt(nightsNumberStr) : 0;
     105        int numPeople = Integer.parseInt(numPeopleStr);
    104106        String queryDate = "";
    105107        boolean dateFlag = false;
     
    121123        List<Option> options;
    122124        try {
    123             options = DatabaseUtil.queryOptions(destination, queryDate, dateFlag);
     125            options = DatabaseUtil.queryOptions(destination, queryDate, numPeople, dateFlag);
    124126        } catch (SQLException e) {
    125127            e.printStackTrace();
  • backend/GlobeGuru-backend/src/main/java/Option.java

    rc164f8f r53bad7e  
    88    private String link;
    99    private String imgSrc;
    10 
     10    private int numPeople;
    1111    //Price changing
    1212    private float newPrice = 0;
     
    6969    }
    7070
     71    public int getNumPeople() {
     72        return numPeople;
     73    }
     74
     75    public void setNumPeople(int numPeople) {
     76        this.numPeople = numPeople;
     77    }
     78
    7179    @Override
    7280    public boolean equals(Object obj) {
  • backend/GlobeGuru-backend/src/main/java/ScraperThread.java

    rc164f8f r53bad7e  
    5858    }
    5959
    60     private void connectToWeb(String queryUrl) {
     60    private void connectToWeb(String queryUrl, int numPeople) {
    6161        driver.get(queryUrl);
    6262
     
    6565            case "https://booking.escapetravel.mk/":
    6666                wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#hotels-container")));
    67                 try { Thread.sleep(5000);} catch (InterruptedException e) { e.printStackTrace(); }
     67                try { Thread.sleep(10000);} catch (InterruptedException e) { e.printStackTrace(); }//price fetch
    6868                break;
    6969            case "https://magelantravel.mk/":
     
    8282
    8383        switch (url) {
    84             case "https://www.fibula.com.mk/":
    85                 parentDiv = doc.selectFirst("div.flex.flex-col.gap-5");
    86                 if (parentDiv != null) {
    87                     childDivs = parentDiv.select("div");
    88                     for (Element div : childDivs) {
    89                         String data = div.html();
    90                         Option option = optionParser(data);
    91                         if (option != null && optionSet.add(option)) {
    92                             uniqueOptions.add(option);
    93                             System.out.println("Parsed " + option);
    94                         }
    95                     }
    96                 } else {
    97                     System.out.println("Parent div not found");
    98                 }
    99                 break;
    10084            case "https://booking.escapetravel.mk/":
    10185                parentDiv = doc.selectFirst("#hotels-container");
     
    10488                    for (Element div : childDivs) {
    10589                        String data = div.outerHtml();
    106                         Option option = optionParser(data);
     90                        Option option = optionParser(data,numPeople);
    10791                        if (option != null) {
    10892                            Option existingOption = DatabaseUtil.findOption(option);
     
    133117                    for (Element div : childDivs) {
    134118                        String data = div.outerHtml();
    135                         Option newOption = optionParser(data);
     119                        Option newOption = optionParser(data,numPeople);
    136120                        if (newOption != null) {
    137121                            Option existingOption = DatabaseUtil.findOption(newOption);
     
    161145
    162146
    163     private Option optionParser(String data) {
     147    private Option optionParser(String data, int numPeople) {
    164148        Document doc = Jsoup.parse(data);
    165149        Option created = new Option();
     
    167151            case "https://magelantravel.mk/":
    168152                created = parseMagelan(doc);
     153                created.setNumPeople(numPeople);
    169154                break;
    170155            case "https://booking.escapetravel.mk/":
    171156                created = parseEscapeTravel(doc);
     157                created.setNumPeople(numPeople);
    172158                break;
    173159            default:
     
    210196        created.setHotelName(card.attr("data-title"));
    211197        Element countryP = doc.selectFirst("p.text-info");
    212         created.setCountry(countryP != null ? countryP.text() : null);
     198        String country = countryP.text().replaceAll("leto hoteli", "");
     199        created.setCountry(country);
    213200        Element priceElem = doc.selectFirst("span.hotel-price");
    214201        String priceText = priceElem.text();
     
    267254                        String country = countryNode.asText();
    268255                        for (int nokevanja = 2; nokevanja <= 10; nokevanja++) {
    269                             String queryUrl = url + "/destinacii?ah_tip=1&iframe=&affiliate_code=&carter_id=0&carter_region=&carter_dataod=&carter_datado=&destinacija=" + country + "&oddatum=" + date + "&nokevanja=" + nokevanja + "&dodatum=&broj_vozrasni=2&broj_deca=0&spdete1=0&spdete2=0&spdete3=0&spdete4=0";
    270                             connectToWeb(queryUrl);
     256                            for(int lugje = 1; lugje <= 4; lugje++) {
     257                                String queryUrl = url + "/destinacii?ah_tip=1&iframe=&affiliate_code=&carter_id=0&carter_region=&carter_dataod=&carter_datado=&destinacija=" + country + "&oddatum=" + date + "&nokevanja=" + nokevanja + "&dodatum=&broj_vozrasni=" + lugje + "&broj_deca=0&spdete1=0&spdete2=0&spdete3=0&spdete4=0";
     258                                connectToWeb(queryUrl,lugje);
     259                            }
    271260                        }
    272261                    }
     
    282271                ClassLoader classLoader = getClass().getClassLoader();
    283272                JsonNode root = mapper.readTree(new File(classLoader.getResource("CountriesList.json").getFile()));
    284                 JsonNode countries = root.get("countries"); // Assuming "destinations" key in JSON
     273                JsonNode countries = root.get("countries");
    285274                SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
    286275                Calendar calendar = Calendar.getInstance();
     
    292281                        String country = countryNode.asText();
    293282                        for(int nokevanja = 2; nokevanja <=10; nokevanja ++) {
    294                             String queryUrl = url + "/hotels?Search=" + country + "&Date=" + date + "&Nights=" + nokevanja + "&Rooms=1&Adults=2";
    295                             connectToWeb(queryUrl);
     283                            for(int lugje = 1; lugje <= 4; lugje++) {
     284                                String queryUrl = url + "/hotels?Search=" + country + "&Date=" + date + "&Nights=" + nokevanja + "&Rooms=1&Adults=" + lugje;
     285                                connectToWeb(queryUrl,lugje);
     286                            }
    296287                        }
    297288                    }
  • backend/GlobeGuru-backend/src/main/java/Server.java

    rc164f8f r53bad7e  
    2828import java.time.LocalDateTime;
    2929import java.time.format.DateTimeFormatter;
     30import java.time.temporal.ChronoUnit;
    3031import java.util.*;
    3132import java.util.concurrent.ExecutorService;
     
    3435
    3536public class Server {
    36 
     37    private static final ExecutorService executorService = Executors.newFixedThreadPool(1);
    3738    public static void main(String[] args) throws IOException, SQLException {
    3839        // Start HTTP server
     
    5758
    5859        server.start();
    59 
    6060        System.out.println("Server started on port 8000");
     61
     62        LocalDateTime lastUpdateTime = getLastUpdateTime();
     63        LocalDateTime now = LocalDateTime.now();
     64        if (ChronoUnit.MONTHS.between(lastUpdateTime, now) >= 3) {
     65            System.out.println("Automatic Update");
     66            Future<Void> future = executorService.submit(new Scraper());
     67            Server.updateLastUpdateTime();
     68            executorService.submit(() -> {
     69                try {
     70                    future.get();
     71                } catch (Exception e) {
     72                    e.printStackTrace();
     73                }
     74            });
     75
     76        }
     77
    6178    }
    6279    static class RemoveFromSavedTripsHandler implements HttpHandler {
  • backend/GlobeGuru-backend/target/classes/lastUpdateTime.json

    rc164f8f r53bad7e  
    11{
    2   "lastUpdateTime" : "2025-01-09T17:43:12.148699200"
     2  "lastUpdateTime" : "2025-01-09T19:56:28.178946100"
    33}
  • frontend/index.html

    rc164f8f r53bad7e  
    3737            <label for="Nights">Број на ноќи</label>
    3838            <input type="number" id="Nights" name="nightsNumber">
     39            <label for="NumPeople">Број на лица</label>
     40            <input type="number" id="NumPeople" name="numberPeople" min="0" max="4" value="0" placeholder="внесете 0 за без ограничување">
    3941            <input type="submit" class="button" value="Пребарај" >
    4042        </form>
  • frontend/js/formHandler.js

    rc164f8f r53bad7e  
    11document.addEventListener('DOMContentLoaded', function() {
    2     const form = document.getElementById('form-id'); // Ensure the form has the correct ID
     2    const form = document.getElementById('form-id');
    33    const loadingOverlay = document.getElementById('loadingOverlay');
    44
     
    2727                errorMessage += "Внесете дестинација.\n";
    2828            }
    29 
    3029        });
    3130
     
    3534        }
    3635
    37         // Show the loading overlay
    3836        loadingOverlay.style.display = 'flex';
    3937
     
    4846            .then(response => response.json())
    4947            .then(data => {
    50 
    5148                loadingOverlay.style.display = 'none';
    5249
     
    6461                    const optionDiv = document.createElement('div');
    6562                    optionDiv.classList.add('option');
    66                     //Option from
    6763
    6864                    //image
    6965                    const img = document.createElement('img');
    7066                    img.classList.add('image');
    71                     img.src = item.imgSrc; // Use item.imageSrc if available
     67                    img.src = item.imgSrc;
    7268                    optionDiv.appendChild(img);
    7369                    const WrapperDiv = document.createElement('div');
     
    8985                    dateParagraph.textContent = item.dateRange;
    9086                    WrapperDiv.appendChild(dateParagraph);
     87                    const peopleParaghraph = document.createElement('p');
     88                    peopleParaghraph.id = 'numPeople';
     89                    if(item.numPeople === 1){
     90                    peopleParaghraph.textContent = item.numPeople + " лице";
     91                    }
     92                    else peopleParaghraph.textContent = item.numPeople + " лица";
     93                    WrapperDiv.appendChild(peopleParaghraph);
     94
     95                    const infoDiv = document.createElement('div');
     96
     97
     98
     99
    91100                    //price
    92101                    const priceHeading = document.createElement('h1');
     
    97106                    priceParagraph.textContent = item.price + "EUR";
    98107                    WrapperDiv.appendChild(priceParagraph);
     108
     109
    99110
    100111                    //  link and button
     
    124135
    125136                    optionDiv.appendChild(btnWrapDiv);
    126                     // Append option div to dataList
    127137                    dataList.appendChild(optionDiv);
    128138                });
     
    131141            .catch(error => {
    132142                console.error('Error fetching data:', error);
    133                 // Hide the loading overlay in case of error
    134143                loadingOverlay.style.display = 'none';
    135144            });
Note: See TracChangeset for help on using the changeset viewer.