Sherlock / components / backend.tsx
backend.tsx
Raw
import { supabase } from "./supabase";


// let apiUrl = "http://10.0.0.218:3000/api";
// let apiUrl = "http://192.168.126.126:3000/api";
let apiUrl = "https://server.sherlock.noahvanfleet.com/api"


/**
 * Wrapper function for timeout implementation
 * @param ms milliseconds
 * @param promise promise to be resolved
 * @returns promise
 */
export function timeout(ms:any, promise:any){
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            reject(new Error("Timed out"));
        },ms)
        promise.then(resolve, reject);
    })
}


/**
 * Function to test connection to backend
 * @returns A ping message
 */
export async function testConnection(): Promise<any>{
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        return fetch(apiUrl+"/test", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            }
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error testing connection: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error testing connection: ", error);
        throw error;
    }
}

/**
 * Gets all kpd cip data
 * @param lat 
 * @param long 
 * @param latDelt 
 * @param longDelt 
 * @returns array of marker objects
 */
export async function getKPDCIP(lat:any, long:any, latDelt:any, longDelt:any): Promise<any>{
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/kpd_cip");
        url.searchParams.append("lat", lat);
        url.searchParams.append("long", long);
        url.searchParams.append("latDelt", latDelt);
        url.searchParams.append("longDelt", longDelt);

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response) => response.json()).then(json => {
            // console.log("RES: ",json);
            return json;
        }).catch((error) => {
            console.error("Error fetching kpd_cip: ",error);
            throw error;
        });
    }catch(error){
        console.error("Error fetching kpd_cip: ",error);
        throw error;
    }
}


    //Gets marker data for county
    /**
     * Gets marker data for specified county
     * @param county 
     * @returns list of marker objects
     */
    export async function getCounty(county:string){
        try{
            const { data, error } = await supabase.auth.getSession()
            if(error){
                console.log("Error getting session: ", error);
                throw error;
            }

            if (data.session?.access_token == undefined) {
                return;
            }

            let url = new URL(apiUrl+"/county");
            url.searchParams.append("county", county);

            return fetch(url, {
                method: 'GET',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                },
            }).then((response)=>response.json()).then(json=>{return json;}).catch((error)=>{
                console.log("Error fetching data for specified county: ", error);
                throw error;
            })
        }catch(error){
            console.log("Error fetching data for specified county: ", error);
            throw error;
        }
    }

    /**
     * Gets marker data for specified marker
     * @param id id of the marker
     * @param source a number corresponding to the source of the marker
     * @returns marker object
     */
    export async function getMarkerByID(id:any, source:any){
        try{
            const { data, error } = await supabase.auth.getSession()
            if(error){
                console.log("Error getting session: ", error);
                throw error;
            }

            if (data.session?.access_token == undefined) {
                return;
            }

            let url = new URL(apiUrl+"/markerById");
            url.searchParams.append("id", id);
            url.searchParams.append("source", source);
            
            return fetch(url, {
                method: 'GET',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                },
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return json;
            }).catch((error)=>{
                console.log("Error fetching data for specified marker: ", error);
                throw error;
            })
        }catch(error){
            console.log("Error fetching data for specified marker: ", error);
            throw error;
        }
    }

    /**
     * Gets marker by coords and time
     * @param coords object containing latitude and longitude
     * @param time 
     * @returns marker object
     * @deprecated There is no longer a need for this.
     */
    export async function getMarkerByLocation(coords:any, time:any){
        try{
            const { data, error } = await supabase.auth.getSession()
            if(error){
                console.log("Error getting session: ", error);
                throw error;
            }

            if (data.session?.access_token == undefined) {
                return;
            }

            let url = new URL(apiUrl+"/markerByLocation");
            url.searchParams.append("lat", coords.latitude);
            url.searchParams.append("long", coords.longitude);
            url.searchParams.append("time", time);


            return fetch(url, {
                method: 'GET',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                },
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return json;
            }).catch((error)=>{
                console.log("Error fetching data for specified marker: ", error);
                throw error;
            })
        }catch(error){
            console.log("Error fetching data for specified marker: ", error);
            throw error;
        }
        
    }

    /**
     * Gets all marker data from desired county
     * @param county defaults to 'knox'. String of desired county info
     * @returns array of marker objects
     */
    export async function getDefaultCounty(county:string="knox"){
        try{
            const { data, error } = await supabase.auth.getSession()
            if(error){
                console.log("Error getting session: ", error);
                throw error;
            }

            if (data.session?.access_token == undefined) {
                return;
            }

            let url = new URL(apiUrl+"/county");
            url.searchParams.append("county", county);

            return fetch(url, {
                method: 'GET',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                },
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return json;
            }).catch((error)=>{
                console.log("Error fetching default markers: ", error);
                throw error;
            })
        }catch(error){
            console.log("Error fetching default markers: ", error);
            throw error;
        }
    }

    /**
     * Gets all marker data with applied filter from desired county
     * @param date string of how many days back. Options include 2,4,7,14,30
     * @param class1 boolean for class 1 markers displayed
     * @param dog boolean for if dangerous dog markers are displayed
     * @param sor boolean for if sor data is displayed
     * @returns array of marker objects
     * @note sor maybe not be called in this backend and call SOR api when implemented
     */
    export async function getCustomFilter(date:string="2", class1:Boolean=false, dog:Boolean=false, sor:Boolean=false, county:string="knox"){
        try{
            const { data, error } = await supabase.auth.getSession()
            if(error){
                console.log("Error getting session: ", error);
                throw error;
            }

            if (data.session?.access_token == undefined) {
                return [];
            }

            return fetch(apiUrl+"/customFilter", {
                method: 'POST',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                },
                body:JSON.stringify({
                    date:date,
                    class1:class1,
                    dog:dog,
                    sor:sor,
                    county:county
                })
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return [json, {date:date, class1:class1, dog:dog, sor:sor, county:county}];
            }).catch((error)=>{
                console.log("Error fetching custom filter: ", error);
                throw error;
            })
        }catch(error){
            console.log("Error fetching custom filter: ", error);
            throw error;
        }
    }

    /**
     * Gets all class incident classification data
     * @returns object of class incident arrays
     */
    export async function getClassIncidents(){
        try{
            const { data, error } = await supabase.auth.getSession()
            if(error){
                console.log("Error getting session: ", error);
                throw error;
            }

            if (data.session?.access_token == undefined) {
                return;
            }

            return fetch(apiUrl+"/getClassIncidents", {
                method: 'GET',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                }
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return json;
            }).catch((error)=>{
                console.log("Error fetching class incidents: ", error);
                throw error;
            })
        }catch(error){
            console.log("Error fetching class incidents: ", error);
            throw error;
        }
    }


/**
 * Gets stats for a location
 * @param lat 
 * @param long 
 * @param event for specific event. 0 for integration stats, 1 for sheet stats, 2 for location stats
 * @returns ai prediction, recent crime counts
 */
export async function getStats(lat:number=0, long:number=0, event=0, county="knox"){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if (data.session?.access_token == undefined) {
                return;
            }

        let url = new URL(apiUrl+"/stats");
        url.searchParams.append("lat", lat.toString());
        url.searchParams.append("long", long.toString());
        url.searchParams.append("event", event.toString());
        //Default to Knox county
        url.searchParams.append("county", county);

        return fetch(url,{
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching stats: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching stats: ", error);
        throw error;
    }
}


/**
 * Gets SOR data from TBI
 */
export async function getSor(){
    try{
        return fetch(
            "https://tnmap.tn.gov/arcgis/rest/services/PUBLIC_SAFETY/TBI_SEX_OFFENDER_REGISTRY/MapServer/0/query?where=ResCounty%20%3D%20'KNOX'%20AND%20%20(StatusCode%20%3D%20'A'%20OR%20StatusCode%20%3D%20'AI')%20&outFields=Tid,OffenseDate,ResCounty,LastName,FirstName,MiddleName,ResAddr1,ResAddr2,ResCity,ResState,ResZip,Race,Sex,Dob,Ols,Tca1,Tca2,Tca3,Tca4,Tca5,Site,Current_Receive_Date,Univ_Name,Univ_County,Univ_Ori_Code,Univ_Status,Last_Name_1,First_Name_1,Middle_Name_1,CREATE_DATE,ResStartDate,UnivStartDate,Classification,StatusCode,UNIV_CITY,homeless,latitude_employer,longitude_employer,tcacode1,tcacode2,tcacode3,tcacode4,tcacode5,Oln,EmpCounty&outSR=4326&f=json", {
                method: 'GET',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                }
            }).then((response)=>{return response.json()}).then(json=>{return json.features}).catch((error)=>{
                console.error("Error fetching SOR data: ",error);
                throw error;
            })
    }catch(error){
        console.error("Error fetching SOR data: ",error);
        throw error;
    }
}

/**
 * Gets user alias incident data
 */
export async function getUserAlias(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if (data.session?.access_token == undefined) {
                return;
            }


        return fetch(apiUrl+"/userAlias", {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            }
        }).then((response)=>{
            return response.json()
        })
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching user alias : ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching user alias: ", error);
        throw error;
    }
}

/**
 * Gets current counts of current user
 * @returns object of user counts. Including: post_count, comment_count, like_count, verification_score, verifiedpost_count
 */
export async function getUserCounts(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if (data.session?.access_token == undefined) {
                return;
            }

        return fetch(apiUrl+"/userCounts", {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            }
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching user counts: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching user counts: ", error);
        throw error;
    }
}

/**
 * Creates new user in sherlock database
 * @returns 
 */
export async function createUser(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            console.log("Access token is null");
            throw new Error("Access token is null");
        }

        let url = new URL(apiUrl+"/user");

        return fetch(url,{
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            }
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error creating user : ", error);
            throw error;
        })
    }catch(error){
        console.log("Error creating user: ", error);
        throw error;
    }

}

/**
 * Deletes user from both sherlock db and supabase
 * @returns server response
 */
export async function deleteUser(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if (data.session?.access_token == undefined) {
            return;
        }

        return fetch(apiUrl+"/user", {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            }
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting user: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting user: ", error);
        throw error;
    }
}

/**
 * Gets post data
 * @param postId The id of the post
 * @returns post object containing posts content, as well as comments and upvote count
 */
export async function getPost(postId:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if (data.session?.access_token == undefined) {
            return;
        }

        let url = new URL(apiUrl+"/post");
        url.searchParams.append("postId", postId.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching post: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching post: ", error);
        throw error;
    }
}

/**
 * Gets initial posts. Contains both posts and report posts
 * @returns an object containing posts and report posts
 */
export async function getInitPosts(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/initPosts", {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            }
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching posts :", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching posts: ", error);
        throw error;
    }
}

/**
 * Gets feed data from backend
 * @param newest highest eid from feed
 * @param oldest lowest eid from feed
 * @returns object containing posts and report posts
 */
export async function getFeed(newest:number, oldest:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/feed");
        url.searchParams.append("newest", newest.toString());
        url.searchParams.append("oldest", oldest.toString());


        return fetch(url,{
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching feed: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching feed: ", error);
        throw error;
    }
}

/**
 * Gets newer posts from backend
 * @param eid 
 * @returns 
 */
export async function getNewerPosts(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/newerPosts");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching newer posts: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching newer posts: ", error);
        throw error;
    }
}

export async function getOlderPosts(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/olderPosts");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching older posts: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching older posts: ", error);
        throw error;
    }
}

/**
 * Gets all posts of a user
 * @note This is used for the user profile screen
 * @returns array of posts
 */
export async function getUserPosts(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/userPosts");

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error fetching user posts: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching user posts: ", error);
        throw error;
    }
}

/**
 * Gets all comments made by the user
 * @returns array of user comments
 */
export async function getAllUserComments(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/allUserComments");
        
        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json.rows;
        }).catch((error)=>{
            console.log("Error fetching user comments: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error fetching user comments: ", error);
        throw error;
    }
}

/**
 * function for liking entity
 * @param eid entity id
 * @returns response from backend
 */
export async function likeEntity(eid:number) {
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/likeEntity", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                eid:eid
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error liking entity: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error liking entity: ", error);
        throw error;
    }
}

/**
 * Dislikes entity
 * @param eid 
 * @returns id of dislike
 */
export async function dislikeEntity(eid:number) {
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/dislikeEntity", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                eid:eid
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error disliking entity: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error disliking entity: ", error);
        throw error;
    }
}

/**
 * unlikes an entity
 * @param eid entity id
 * @returns response from backend
 */
export async function unlikeEntity(eid:number) {
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/entityLike");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error unliking entity: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error unliking entity: ", error);
        throw error;
    }
}

/**
 * Gets like and comment counts from entity table
 * @param eid entity id
 * @returns backend response
 */
export async function getEntityCounts(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/entityCounts");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error getting entity counts: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error getting entity counts: ", error);
        throw error;
    }
}

/**
 * Checks to see if a user has liked an entity
 * @param eid entity
 * @returns server resoinse, boolean
 */
export async function hasLiked(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/hasLiked");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            if(response.status == 200){
                return response.json()
            }else{
                console.log(response.json())
            }
        })
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("backend error checking user liked: ", error);
            throw error;
        })
    }catch(error){
        console.log("checking liked error", error);
        throw error;
    }
}

/**
 * Gets comments for an entity
 * @param eid 
 * @returns 
 */
export async function getComments(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/comments");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error getting comments: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error getting comments: ", error);
        throw error;
    }
}

/**
 * Gets comments after a certain comment id
 * @param eid entity 
 * @param cid comment
 * @returns server reponse, aka an array of comment object
 */
export async function getCommentsAfter(eid:number, cid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/commentsAfter");
        url.searchParams.append("eid", eid.toString());
        url.searchParams.append("cid", cid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error getting comments: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error getting comments: ", error);
        throw error;
    }
}

/**
 * Creates a comment
 * @param eid 
 * @param comment 
 * @returns response from server aka comment id
 */
export async function createComment(eid:number, comment:string){
    console.log("Creating comment: ", eid, comment);
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/comment", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                eid:eid,
                text:comment
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error creating comment: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error creating comment: ", error);
        throw error;
    }
}

/**
 * Deletes a comment
 * @param cid comment id
 * @returns reponse from server, aka success message
 */
export async function deleteComment(cid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/comment");
        url.searchParams.append("cid", cid.toString());

        return fetch(url, {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting comment: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting comment: ", error);
        throw error;
    }
}

/**
 * Likes a comment
 * @param cid comment id
 * @returns response frome server, aka like id
 */
export async function likeComment(cid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/likeComment", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                cid:cid
            })
        }).then((response)=>{
            return response.json()})
        .then((json)=>{
            return json;
        }).catch((error)=>{
            throw error;
        })
    }catch(error){
        console.log("Error liking comment: ", error);
        throw error;
    }
}

/**
 * dislikes a comment
 * @param cid comment id
 * @returns response from server, aka like id
 */
export async function dislikeComment(cid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/dislikeComment", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                cid:cid
            })
        }).then((response)=>{
            return response.json()})
        .then((json)=>{
            return json;
        }).catch((error)=>{
            console.log("Error disliking comment: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error disliking comment: ", error);
        throw error;
    }
}

/**
 * Deletes a comment like
 * @param cid comment id
 * @returns success message from server
 */
export async function deleteCommentLike(cid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/commentLike");
        url.searchParams.append("cid", cid.toString());

        return fetch(url, {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then((json)=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting comment like: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting comment like: ", error);
        throw error;
    }
}

/**
 * Checks if a user has liked a comment
 * @param cid comment id
 * @returns response from server, aka sentiment of like. None being no like
 */
export async function hasLikedComment(cid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/hasLikedComment?cid="+cid, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then((json)=>{
            return json;
        }).catch((error)=>{
            console.log("Error checking if comment is liked: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error checking if comment is liked: ", error);
        throw error;
    }
}

/**
 * Gets all ids of comments for a user in a given entity
 * @param eid entity
 * @returns array of comment ids
 */
export async function getUserComments(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/userComments");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error getting user comments: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error getting user comments: ", error);
        throw error;
    }
} 

/**
 * Creates a new post
 * @param body 
 * @returns server response, aka post id
 */
export async function createPost(body:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/post");

        return fetch(url, {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                text:body
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            console.log("Post created: ", json);
            return json;
        }).catch((error)=>{
            console.log("Error creating post: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error creating post: ", error);
        throw error;
    }
}

/**
 * deletes an entity
 * @param eid 
 * @returns server resoinse
 */
export async function deleteEntity(eid:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/entity");
        url.searchParams.append("eid", eid.toString());

        return fetch(url, {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting post: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting post: ", error);
        throw error;
    }
}

/**
 * End point to report a post
 * @param eid entity id
 * @param reason reason for report
 * @returns server response
 */
export async function reportPost(eid:number, reason:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/reportPost", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                eid:eid,
                reason:reason
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error reporting post: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error reporting post: ", error);
        throw error;
    }
}

/**
 * Reports a comment
 * @param cid comment id
 * @param reason reason for report
 * @returns server response
 */
export async function reportComment(cid:number, reason:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/reportComment", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                cid:cid,
                reason:reason
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error reporting comment: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error reporting comment: ", error);
        throw error;
    }
}

/**
 * Deletes a post moderation report
 * @param id id of the report
 * @returns server response
 */
export async function deletePostReport(id:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/reportPost");
        url.searchParams.append("id", id.toString());

        return fetch(url, {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting post report: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting post report: ", error);
        throw error;
    }
}

/**
 * Deletes a moderation report for a comment
 * @param id id of the comment report
 * @returns server response
 */
export async function deleteCommentReport(id:number){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        let url = new URL(apiUrl+"/reportComment");
        url.searchParams.append("id", id.toString());

        return fetch(url, {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting comment report: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting comment report: ", error);
        throw error;
    }
}

/**
 * Subscribes to a topic for notifications
 * @param topic topic for user to subscribe to
 * @returns server repsonse
 */
export async function subscribe(topic:string[]|string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/subscription", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                topic:topic
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error subscribing: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error subscribing: ", error);
        throw error;
    }
}

/**
 * Unsubscribes a user from a topic
 * @returns server response
 */
export async function subscribeDefault(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/subscription/default", {
            method: 'PUT',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error subscribing: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error subscribing: ", error);
        throw error;
    }
}

/**
 * Unsubscribes a user from a topic
 * @param topic topic to unscubscribe from
 * @returns server response
 */
export async function deleteSubscription(topic:string|string[]){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/subscription", {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                topic:topic
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error unsubscribing: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error unsubscribing: ", error);
        throw error;
    }
}

/**
 * Unsubscribes a user from all topics
 * @returns server response
 * @warning WILL CLEAR ALL SUBSCRIPTIONS
 */
export async function deleteSubscriptions(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/subscriptions", {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error unsubscribing: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error unsubscribing: ", error);
        throw error;
    }
}

/**
 * Gets all topics a user is subscribed to
 * @returns server response
 */
export async function getSubscriptions(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/subscription", {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error getting subscriptions: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error getting subscriptions: ", error);
        throw error;
    }
}

/**
 * Adds device to db
 * @param token expo token
 * @param name device name
 * @param version app version
 * @param os os
 * @returns server response
 */
export async function addDevice(token:string, name:string, version:string, os:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return fetch(apiUrl+"/device", {
                method: 'POST',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                },
                body:JSON.stringify({
                    token:token,
                    name:name,
                    app_version: version,
                    os:os,
                })
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return json;
            }).catch((error)=>{
                console.log("Error adding device: ", error);
                throw error;
            })
        }else{
            return fetch(apiUrl+"/device", {
                method: 'POST',
                headers: {
                    Accept:'application/json',
                    'Content-Type':'application/json',
                    Authorization: "Bearer " + data.session?.access_token
                },
                body:JSON.stringify({
                    token:token,
                    name:name,
                    app_version: version,
                    os:os,
                })
            }).then((response)=>{
                return response.json()})
            .then(json=>{
                return json;
            }).catch((error)=>{
                console.log("Error adding device: ", error);
                throw error;
            })
        }
    }catch(error){
        console.log("Error adding device: ", error);
        throw error;
    }
}

/**
 * Deletes added device
 * @param token expo token
 * @returns server response
 */
export async function deleteDevice(token:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/device", {
            method: 'DELETE',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                token:token
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error deleting device: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error deleting device: ", error);
        throw error;
    }
}

/**
 * gets all user devices
 * @returns server response
 */
export async function getDevices(){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/device", {
            method: 'GET',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error getting devices: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error getting devices: ", error);
        throw error;
    }
}

/**
 * Logs in a device/Sets device to a user
 * @param token expo token
 * @returns server response
 */
export async function deviceLogin(token:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/device/login", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                token:token,
            })
        }).then((response)=>{
            if(response.status!=200){
                throw new Error(String(response.status))
            }
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error logging in device: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error logging in device: ", error);
        throw error;
    }
}

/**
 * unassociates device with account
 * @param token expo token
 * @returns server response
 */
export async function deviceLogout(token:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/device/logout", {
            method: 'POST',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                token:token,
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error logging out device: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error logging out device: ", error);
        throw error;
    }
}

/**
 * Updates app version for a device
 * @param token expo token
 * @param version app version
 * @returns server response
 */
export async function updateAppVersion(token:string, version:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/device/app_version", {
            method: 'PUT',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                token:token,
                version:version
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error updating device version: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error updating device version: ", error);
        throw error;
    }
}

/**
 * Updates device name in backend
 * @param name device name
 * @returns server response
 */
export async function updateDeviceName(name:string){
    try{
        const { data, error } = await supabase.auth.getSession()
        if(error){
            console.log("Error getting session: ", error);
            throw error;
        }

        if(data.session?.access_token == undefined){
            return;
        }

        return fetch(apiUrl+"/device/name", {
            method: 'PUT',
            headers: {
                Accept:'application/json',
                'Content-Type':'application/json',
                Authorization: "Bearer " + data.session?.access_token
            },
            body:JSON.stringify({
                name:name,
            })
        }).then((response)=>{
            return response.json()})
        .then(json=>{
            return json;
        }).catch((error)=>{
            console.log("Error updating device name: ", error);
            throw error;
        })
    }catch(error){
        console.log("Error updating device name: ", error);
        throw error;
    }
}