<commit_before>package org.openforis.ceo;

import static org.openforis.ceo.JsonUtils.filterJsonArray;
import static org.openforis.ceo.JsonUtils.findInJsonArray;
import static org.openforis.ceo.JsonUtils.getNextId;
import static org.openforis.ceo.JsonUtils.intoJsonArray;
import static org.openforis.ceo.JsonUtils.mapJsonFile;
import static org.openforis.ceo.JsonUtils.parseJson;
import static org.openforis.ceo.JsonUtils.readJsonFile;
import static org.openforis.ceo.JsonUtils.toStream;
import static org.openforis.ceo.JsonUtils.writeJsonFile;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import spark.Request;
import spark.Response;

public class Users {

    public static Request login(Request req, Response res) {
        String inputEmail = req.queryParams("email");
        String inputPassword = req.queryParams("password");
        // Check if email exists
        JsonArray users = readJsonFile("user-list.json").getAsJsonArray();
        Optional<JsonObject> matchingUser = findInJsonArray(users, user -> user.get("email").getAsString().equals(inputEmail));
        if (matchingUser.isPresent()) {
            // Check if password matches
            JsonObject user = matchingUser.get();
            String userId = user.get("id").getAsString();
            String userPassword = user.get("password").getAsString();
            String userRole = user.get("role").getAsString();
            if (inputPassword.equals(userPassword)) {
                // Authentication successful
                req.session().attribute("userid", userId);
                req.session().attribute("username", inputEmail);
                req.session().attribute("role", userRole);
                res.redirect(Server.documentRoot + "/home");
            } else {
                // Authentication failed
                req.session().attribute("flash_messages", new String[]{"Invalid email/password combination."});
            }
        } else {
            req.session().attribute("flash_messages", new String[]{"No account with email " + inputEmail + " exists."});
        }
        return req;
    }

    protected static boolean isEmail(String email) {
        String emailPattern = "(?i)[a-z0-9!#$%&'*+/=?^_`{|}~-]+" +
            "(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*" +
            "@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+" +
            "[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
        return Pattern.matches(emailPattern, email);
    }

    public static synchronized Request register(Request req, Response res) {
        String inputEmail = req.queryParams("email");
        String inputPassword = req.queryParams("password");
        String inputPasswordConfirmation = req.queryParams("password-confirmation");
        // Validate input params and assign flash_messages if invalid
        if (isEmail(inputEmail)) {
            if (inputPassword.length() >= 8) {
                if (inputPassword.equals(inputPasswordConfirmation)) {
                    JsonArray users = readJsonFile("user-list.json").getAsJsonArray();
                    Optional<JsonObject> matchingUser = findInJsonArray(users, user -> user.get("email").getAsString().equals(inputEmail));

                    if (matchingUser.isPresent()) {
                        req.session().attribute("flash_messages", new String[]{"Account " + inputEmail + " already exists."});
                    } else {
                        // Add a new user to user-list.json
                        int newUserId = getNextId(users);
                        String newUserRole = "user";

                        JsonObject newUser = new JsonObject();
                        newUser.addProperty("id", newUserId);
                        newUser.addProperty("email", inputEmail);
                        newUser.addProperty("password", inputPassword);
                        newUser.addProperty("role", newUserRole);
                        newUser.add("reset_key", null);
                        newUser.add("ip_addr", null);

                        users.add(newUser);
                        writeJsonFile("user-list.json", users);

                        // Update institution-list.json
                        mapJsonFile("institution-list.json",
                                    institution -> {
                                        if (institution.get("name").getAsString().equals("All Users")) {
                                            JsonArray members = institution.get("members").getAsJsonArray();
                                            members.add(newUserId);
                                            institution.add("members", members);
                                            return institution;
                                        } else {
                                            return institution;
                                        }
                                    });

                        // Assign the username and role session attributes
                        req.session().attribute("userid", newUserId);
                        req.session().attribute("username", inputEmail);
                        req.session().attribute("role", newUserRole);

                        // Redirect to the Home page
                        res.redirect(Server.documentRoot + "/home");
                    }
                } else {
                    req.session().attribute("flash_messages", new String[]{"Password and Password confirmation do not match."});
                }
            } else {
                req.session().attribute("flash_messages", new String[]{"Password must be at least 8 characters."});
            }
        } else {
            req.session().attribute("flash_messages", new String[]{inputEmail + " is not a valid email address."});
        }
        return req;
    }

    public static Request logout(Request req) {
        req.session().removeAttribute("userid");
        req.session().removeAttribute("username");
        req.session().removeAttribute("role");
        return req;
    }

    // FIXME: stub
    public static Request updateAccount(Request req, Response res) {
        String accountId = req.params(":id"); // FIXME: Use this
        req.session().attribute("flash_messages", new String[]{"This functionality has not yet been implemented."});
        return req;
    }

    // FIXME: stub
    public static Request getPasswordResetKey(Request req, Response res) {
        req.session().attribute("flash_messages", new String[]{"This functionality has not yet been implemented."});
        return req;
    }

    // FIXME: stub
    public static Request resetPassword(Request req, Response res) {
        req.session().attribute("flash_messages", new String[]{"This functionality has not yet been implemented."});
        return req;
    }

    public static String getAllUsers(Request req, Response res) {<commit_msg>Making some stylistic changes to Users.java to improve readability and camelCased reset_key and ip_addr references.<commit_after>package org.openforis.ceo;

import static org.openforis.ceo.JsonUtils.filterJsonArray;
import static org.openforis.ceo.JsonUtils.findInJsonArray;
import static org.openforis.ceo.JsonUtils.getNextId;
import static org.openforis.ceo.JsonUtils.intoJsonArray;
import static org.openforis.ceo.JsonUtils.mapJsonFile;
import static org.openforis.ceo.JsonUtils.parseJson;
import static org.openforis.ceo.JsonUtils.readJsonFile;
import static org.openforis.ceo.JsonUtils.toStream;
import static org.openforis.ceo.JsonUtils.writeJsonFile;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import spark.Request;
import spark.Response;

public class Users {

    public static Request login(Request req, Response res) {
        String inputEmail = req.queryParams("email");
        String inputPassword = req.queryParams("password");
        // Check if email exists
        JsonArray users = readJsonFile("user-list.json").getAsJsonArray();
        Optional<JsonObject> matchingUser = findInJsonArray(users, user -> user.get("email").getAsString().equals(inputEmail));
        if (matchingUser.isPresent()) {
            // Check if password matches
            JsonObject user = matchingUser.get();
            String storedId = user.get("id").getAsString();
            String storedPassword = user.get("password").getAsString();
            String storedRole = user.get("role").getAsString();
            if (inputPassword.equals(storedPassword)) {
                // Authentication successful
                req.session().attribute("userid", storedId);
                req.session().attribute("username", inputEmail);
                req.session().attribute("role", storedRole);
                res.redirect(Server.documentRoot + "/home");
            } else {
                // Authentication failed
                req.session().attribute("flash_messages", new String[]{"Invalid email/password combination."});
            }
        } else {
            req.session().attribute("flash_messages", new String[]{"No account with email " + inputEmail + " exists."});
        }
        return req;
    }

    protected static boolean isEmail(String email) {
        String emailPattern = "(?i)[a-z0-9!#$%&'*+/=?^_`{|}~-]+" +
            "(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*" +
            "@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+" +
            "[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
        return Pattern.matches(emailPattern, email);
    }

    public static synchronized Request register(Request req, Response res) {
        String inputEmail = req.queryParams("email");
        String inputPassword = req.queryParams("password");
        String inputPasswordConfirmation = req.queryParams("password-confirmation");
        // Validate input params and assign flash_messages if invalid
        if (! isEmail(inputEmail)) {
            req.session().attribute("flash_messages", new String[]{inputEmail + " is not a valid email address."});
        } else if (inputPassword.length() < 8) {
            req.session().attribute("flash_messages", new String[]{"Password must be at least 8 characters."});
        } else if (! inputPassword.equals(inputPasswordConfirmation)) {
            req.session().attribute("flash_messages", new String[]{"Password and Password confirmation do not match."});
        } else {
            JsonArray users = readJsonFile("user-list.json").getAsJsonArray();
            Optional<JsonObject> matchingUser = findInJsonArray(users, user -> user.get("email").getAsString().equals(inputEmail));
            if (matchingUser.isPresent()) {
                req.session().attribute("flash_messages", new String[]{"Account " + inputEmail + " already exists."});
            } else {
                // Add a new user to user-list.json
                int newUserId = getNextId(users);
                String newUserRole = "user";

                JsonObject newUser = new JsonObject();
                newUser.addProperty("id", newUserId);
                newUser.addProperty("email", inputEmail);
                newUser.addProperty("password", <PASSWORD>);
                newUser.addProperty("role", newUserRole);
                newUser.add("resetKey", null);
                newUser.add("ipAddr", null);

                users.add(newUser);
                writeJsonFile("user-list.json", users);

                // Update institution-list.json
                // FIXME: Remove this code block since the "All Users" institution isn't used anywhere
                mapJsonFile("institution-list.json",
                            institution -> {
                                if (institution.get("name").getAsString().equals("All Users")) {
                                    JsonArray members = institution.get("members").getAsJsonArray();
                                    members.add(newUserId);
                                    institution.add("members", members);
                                    return institution;
                                } else {
                                    return institution;
                                }
                            });

                // Assign the username and role session attributes
                req.session().attribute("userid", newUserId);
                req.session().attribute("username", inputEmail);
                req.session().attribute("role", newUserRole);

                // Redirect to the Home page
                res.redirect(Server.documentRoot + "/home");
            }
        }
        return req;
    }

    public static Request logout(Request req) {
        req.session().removeAttribute("userid");
        req.session().removeAttribute("username");
        req.session().removeAttribute("role");
        return req;
    }

    // FIXME: stub
    public static Request updateAccount(Request req, Response res) {
        String accountId = req.params(":id"); // FIXME: Use this
        req.session().attribute("flash_messages", new String[]{"This functionality has not yet been implemented."});
        return req;
    }

    // FIXME: stub
    public static Request getPasswordResetKey(Request req, Response res) {
        req.session().attribute("flash_messages", new String[]{"This functionality has not yet been implemented."});
        return req;
    }

    // FIXME: stub
    public static Request resetPassword(Request req, Response res) {
        req.session().attribute("flash_messages", new String[]{"This functionality has not yet been implemented."});
        return req;
    }

    public static String getAllUsers(Request req, Response res) {
{'fraction_non_alphanumeric': 0.1245005707762557, 'fraction_numerical': 0.0025684931506849314, 'mean_word_length': 2.092894969108561, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5889275', 'n_tokens_mistral': 3536, 'n_tokens_neox': 3437, 'n_words': 773}