# Project export: HuskyLink

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 10.0
- Tagline: Linking programmers across campuses
- Devpost: https://devpost.com/software/huskylink
- GitHub: https://github.com/TenderloinTech/HuskyLink
- Video: https://www.youtube.com/embed/9cM8nxSk_fw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 4 GitHub contributor(s) — Trent Wiles (82 commits), Anish Sahoo (37 commits), Shishir Pokhrel (7 commits), DannySklyarevskiy (3 commits)

## Devpost submission (written by the team)

### Inspiration

At our Northeastern University all-freshman campus, countless students have struggled with finding the help they need to succeed in their CS classes. We decided to make this project to help connect students with collaborators, mentors and peers for CS related help and activities.

### What it does

Helps CS students across Northeastern University campuses find collaborators and peers in their programming journeys.

### How we built it

We used a number of technologies, including Reflex for our frontend, Python Flask for our backend, and Varnish for our cache server.

### Challenges we ran into

Multiple bugs in our code, including issues with Reflex and hosting the API.

### Accomplishments we're proud of

We created a working prototype that incorporated two products, Reflex and CockroachDB, that all team members were unfamiliar with prior to the start of the hackathon.

### What we learned

We learned more about how to develop databases on serverless platforms and gained experience in documenting and deploying full stack web applications.

### What's next

We would like to expand our app across all of Northeastern’s campuses, and eventually release this as a Platform-as-a-service for other universities to use.

## README (from the GitHub repository)

# **Husky Link!**

![](https://trentwil.es/a/thumbnail_photoshop.png?dsfsdf)
Husky Link is a web-app that lets you choose your coding partners easily!

Check out our [**Website**](https://tenderloin.tech)

Check out our [**Instagram**](https://www.instagram.com/tenderloin.tech/)

Video demo: [Here](https://trentwil.es/a/huskylink.mp4)

## What exactly is Husky Link?
Have you ever wanted to attend hackathon, needed help with coding, or even find a coding partner?
Husky link is exactly that!

- Marketplace for introvert and extrovert coders!
  - Put up a application for partners
    OR
  - Find application for partners
  - Find a (coding) partner
  - Make friends, and have fun
  - Dont have to swipe right or swipe left.
- Browse through lists of potential partners for your next hackathon, project, or even homeworks!

#### **DONT WAIT, SIGN UP NOW!**

-Made by Shishir Pokhrel, Trent Wiles, Danny Sklyarevskiy, and Anish Sahoo


## Detected evidence (automated analysis)

Indexed codebase: 38 recognized source files, 93 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- Flask (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (47 of 47)

```
.gitignore
.web/.gitignore
.web/components/reflex/chakra_color_mode_provider.js
.web/components/reflex/radix_themes_color_mode_provider.js
.web/jsconfig.json
.web/next.config.js
.web/package.json
.web/postcss.config.js
.web/reflex.json
.web/styles/code/prism.js
.web/styles/tailwind.css
.web/utils/client_side_routing.js
.web/utils/helpers/dataeditor.js
.web/utils/state.js
API/.gitignore
API/api-test.py
API/config.json.example
API/docs/README.md
API/main.py
API/title-test.py
API/user-test.py
doc/reflex.md
HtmlPrototypes/registerOne.html
HtmlPrototypes/style.css
HuskyLink/__init__.py
HuskyLink/components/__init__.py
HuskyLink/components/sidebar.py
HuskyLink/HuskyLink.py
HuskyLink/pages/__init__.py
HuskyLink/pages/add_request.py
HuskyLink/pages/create_account.py
HuskyLink/pages/dashboard.py
HuskyLink/pages/explore.py
HuskyLink/pages/index.py
HuskyLink/pages/login.py
HuskyLink/pages/profile.py
HuskyLink/pages/user.py
HuskyLink/pages/users.py
HuskyLink/pages/view.py
HuskyLink/state.py
HuskyLink/styles.py
HuskyLink/templates/__init__.py
HuskyLink/templates/template.py
README.md
requirements.txt
rxconfig.py
video.mkv
```

### Dependencies

- .web/package.json: @chakra-ui/icons@2.0.19, @chakra-ui/react@2.6.1, @chakra-ui/system@2.5.7, @emotion/react@^11.11.0, @emotion/styled@^11.11.0, autoprefixer@10.4.14, axios@1.4.0, focus-visible@5.2.0, framer-motion@10.16.4, json5@2.2.3, next@13.5.4, next-sitemap@4.1.8, next-themes@0.2.0, postcss@8.4.24, react@18.2.0, react-dom@18.2.0, react-markdown@8.0.7, react-syntax-highlighter@15.5.0, rehype-katex@6.0.3, rehype-raw@6.1.1, remark-gfm@3.0.1, remark-math@5.1.1, socket.io-client@4.6.1, tailwindcss@3.3.2, universal-cookie@4.0.4
- requirements.txt: reflex@==0.3.1

### Recent commits (newest first)

- Update README.md
- video demo
- cockroach
- new commit
- everything works, finally
- Merge branch 'main' of github.com:TenderloinTech/HuskyLink
- api name picker
- new commit
- Merge branch 'main' of https://github.com/TenderloinTech/HuskyLink
- things work
- get stats endpoint up
- new api route
- Merge branch 'main' of github.com:TenderloinTech/HuskyLink
- new api route
- screenshot
- Update reflex.md
- start reflex docs
- new commit
- some decor
- Merge branch 'main' of https://github.com/TenderloinTech/HuskyLink

## Key source files (fetched from GitHub, selected and truncated for size)

### doc/reflex.md

```markdown
# Reflex Development

We've worked with reflex throughout the hackathon, and here are our findings.

## Deploying Locally

Deploying locally worked initially, but late into the competition, we kept getting websocket errors. It appeared that the websocket server was not working, and we got several "unable to connect to the websocket" errors.

## Deploying to the cloud

Deplying to the Reflex cloud did not work. The reflex cloud, which appeared to be using fly.io, did not work. The program claimed to have failed to deploy our app, but upon reading the deploy logs, nothing seemed to be wrong.

```
──────────────────────────────────────────────────────────────── Deploying production app. ─────────────────────────────────────────────────────────────────
Deployment will start shortly. Closing this command now will not affect your deployment.
Waiting for server to report progress ...
Hosting server reports failure.
Check the server logs using `reflex deployments build-logs huskylink1`
```

Logs of running `reflex deployments build-logs huskylink1`: https://pastebin.com/raw/rAUcpu4J

After viewing the url for the app, huskylink1.reflex.run, the site showed a static version of the app, with what appeared to be cached database data. It then complained it was unable to communicate with the websocket, which was hosted at `rxh-prod-huskylink1.fly.dev`.

![](https://trentwil.es/a/XL7KVtKJM0.png)

```

### requirements.txt

```

reflex==0.3.1

```

### .web/package.json

```
{
  "name": "reflex",
  "scripts": {
    "dev": "next dev",
    "export": "next build && next export -o _static",
    "export-sitemap": "next build && next-sitemap && next export -o _static",
    "prod": "next start"
  },
  "dependencies": {
    "@chakra-ui/icons": "2.0.19",
    "@chakra-ui/react": "2.6.1",
    "@chakra-ui/system": "2.5.7",
    "@emotion/react": "^11.11.0",
    "@emotion/styled": "^11.11.0",
    "axios": "1.4.0",
    "focus-visible": "5.2.0",
    "framer-motion": "10.16.4",
    "json5": "2.2.3",
    "next": "13.5.4",
    "next-sitemap": "4.1.8",
    "next-themes": "0.2.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-markdown": "8.0.7",
    "react-syntax-highlighter": "15.5.0",
    "rehype-katex": "6.0.3",
    "rehype-raw": "6.1.1",
    "remark-gfm": "3.0.1",
    "remark-math": "5.1.1",
    "socket.io-client": "4.6.1",
    "universal-cookie": "4.0.4"
  },
  "devDependencies": {
    "autoprefixer": "10.4.14",
    "postcss": "8.4.24",
    "tailwindcss": "3.3.2"
  }
}
```

### API/main.py

```python
from flask import Flask, request, Response
import psycopg2
import json
import time
import random

# Create a Flask app
app = Flask(__name__)



# Define a route
@app.route('/')
def hello_world():
    return Response(json.dumps({"online": True}), content_type="application/json")

@app.route('/api/v1/getStats')
def stats():
    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    totalUsers = 0

    with conn.cursor() as cur:
        cur.execute(f"select count(*) from users;")
        res = cur.fetchall()
        conn.commit()
        totalUsers = res[0][0]

    totalRequests = 0

    with conn.cursor() as cur:
        cur.execute(f"select count(*) from requests;")
        res = cur.fetchall()
        conn.commit()
        totalRequests = res[0][0]

    return Response(json.dumps({"totalUsers": totalUsers, "totalRequests": totalRequests}), content_type="application/json")
    

@app.route("/api/v1/login", methods=["POST"])
def login():
    user = request.form.get('username').lower()
    password = request.form.get('password')

    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"select * from users where username='{user}'")
        res = cur.fetchall()
        conn.commit()
        print(res)
        if len(res) != 1:
            return Response(json.dumps({"result": {"password": False}}), content_type="application/json")
        if res[0][2] == password:
            return Response(json.dumps({"result": {"password": True}}), content_type="application/json")
    return Response(json.dumps({"result": {"password": False, "returnedPassword": password}}), content_type="application/json")

@app.route("/api/v1/createAccount", methods=["POST"])
def create():

    # Parameters Required
    user = request.form.get('username')
    realName = request.form.get('realName')
    password = request.form.get('password')
    email = request.form.get('email')
    createdAt = round(time.time())
    userType = request.form.get("userType")
    profileImageURL = request.form.get("profileImageURL")
    isBanned = False


    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"select * from users where username='{user}'")
        res = cur.fetchall()
        conn.commit()
        if len(res) != 0:
            if res[0][0] == user:
                return Response(json.dumps({"result": {"success": False, "message": "Username exists"}})), 400

    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"insert into users (username, realName, pass, createdAt, userType, profileImageURL, isBanned, email) values ('{user}', '{realName}', '{password}', {createdAt}, '{userType}', '{profileImageURL}', {isBanned}, '{email}')")
        conn.commit()
    return Response(json.dumps({"result": {"success": True, "message": "ok", "createdAt": createdAt}}), content_type="application/json")

@app.route("/api/v1/getUserInfo/<user>", methods=["GET"])
def uInfo(user):
    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"select username, realName, createdAt, userType, profileImageURL, isBanned, userRole, email from users where username='{user}'")
        res = cur.fetchall()
        conn.commit()
        return Response(json.dumps(res), content_type="application/json")


@app.route("/api/v1/listAllUsers", methods=["GET"])
def lists():
    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"select username, realName, createdAt, userType, profileImageURL, isBanned, userRole, email from users")
        res = cur.fetchall()
        conn.commit()
        return Response(json.dumps(res), content_type="application/json")

@app.route("/api/v1/sortByUserType/<role>")
def sortRole(role):
    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"select username, realName, createdAt, userType, profileImageURL, isBanned, userRole from users where userType='{role}'")
        res = cur.fetchall()
        conn.commit()
        return Response(json.dumps(res), content_type="application/json")

@app.route("/api/v1/searchUsers")
def searchUsers():
    q = request.args.get("q").lower()

    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    hits = []

    with conn.cursor() as cur:
        cur.execute(f"select * from requests")
        res = cur.fetchall()
        conn.commit()

        for x in res:
            if q in x[0] or q in x[1]:
                if x not in hits:
                    hits.append(x)

        return Response(json.dumps(hits), content_type="application/json")

@app.route("/api/v1/createNewRequest", methods=["POST"])
def createReq():
    # Request params

    username = request.form.get('username')
    title = request.form.get("title")
    description = request.form.get("description")
    tags = request.form.get("tags")
    createdAt = round(time.time())
    isActive = True
    randomID = random.randint(0,10000000000)

    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"insert into requests (userUniqueID, title, description, tags, createdAt, isActive, randomID) values ('{username}', '{title}', '{description}', '{tags}', {createdAt}, {isActive}, {randomID})")
        conn.commit()

    return Response(json.dumps({"result": {"uniqueID": randomID}}))
    
@app.route("/api/v1/listRequests")
def listRequests():
    conn = psycopg2.connect(json.loads(open("API/config.json").read())["cockroach"])

    with conn.cursor() as cur:
        cur.execute(f"select * from requests")
        res = cur.fetchall()
 
[truncated — 1719 more characters]
```

### HuskyLink/pages/index.py

```python
"""The home page of the app."""

from HuskyLink import styles
from HuskyLink.templates import template

import reflex as rx


@template(route="/", title="Home", image="/github.svg")
def index() -> rx.Component:
    """The home page.

    Returns:
        The UI for the home page.
    """
    with open("README.md") as readme:
        content = readme.read()
    return rx.markdown(content, component_map=styles.markdown_style)

```

### rxconfig.py

```python
import reflex as rx

config = rx.Config(
    app_name="HuskyLink",
)
```

### HuskyLink/__init__.py

```python
"""Base template for Reflex."""
```

### .web/postcss.config.js

```javascript
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### .web/next.config.js

```javascript
module.exports = {
  basePath: "",
  compress: true,
  reactStrictMode: true,
  trailingSlash: true,
};

```

### HuskyLink/HuskyLink.py

```python
"""Welcome to Reflex!."""

from HuskyLink import styles

# Import all the pages.
from HuskyLink.pages import *

import reflex as rx

# Create the app and compile it.
app = rx.App(style=styles.base_style)
app.compile()
```

[27 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]