Skip to content
Open

Siyi #42

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
0b350f1
Move root folder.
Jan 16, 2024
3b4d5eb
Add requirements.txt file.
Jan 16, 2024
b466844
Remove anaconda from requirements file.
Jan 16, 2024
bcdc4a8
Remove anaconda from requirements file.
Jan 16, 2024
c4b66a0
Purge requirements.txt.
Jan 16, 2024
8b0e2ee
Remove pywatchman from requirements.txt.
Jan 16, 2024
115b72b
Re-add backend folder.
Jan 16, 2024
479836e
Add STATIC_ROOT in settings.py.
Jan 16, 2024
b2c4564
Change static file settings.
Jan 16, 2024
7521bae
Set Debug to false in settings.py.
Jan 16, 2024
dbcd4f7
Add Procfile and runtime.txt.
Jan 16, 2024
e3b3f7f
Add gunicorn to requirement.
Jan 16, 2024
8ee6feb
Add netlify frontend url to cors.
Jan 16, 2024
9fd706a
Remove slash from cors url.
Jan 16, 2024
5cbed3f
Merge branch 'master' into heroku
papataco14 Jan 18, 2024
1a57fe6
Move to root.
juancarlovieri Mar 1, 2024
aa6e761
Merge branch 'move_backend' of github.com:juancarlovieri/nussuwebsite…
juancarlovieri Mar 1, 2024
541625e
Add nussu website on cors.
juancarlovieri Mar 17, 2024
e567e51
Merge branch 'heroku' into latest-changes-28-June
LouisLouis19 Jun 28, 2024
4bdae1b
Move services folder to root
LouisLouis19 Jun 28, 2024
c7403b3
Merge pull request #25 from nussucommit/latest-changes-28-June
LouisLouis19 Jun 28, 2024
b8cac48
Merge branch 'heroku' into heroku-staged
JasonRay168 Aug 7, 2024
f528eba
Make initial changes to ourteam strucure
JasonRay168 Aug 7, 2024
f45e324
Fix module issues
JasonRay168 Aug 7, 2024
f870b31
Merge pull request #27 from nussucommit/heroku-staged
JasonRay168 Aug 7, 2024
08fe896
Merge pull request #28 from nussucommit/jason-ray/ourteam-fix
JasonRay168 Aug 8, 2024
f4f9ec1
update backend env
Blankeeir Aug 12, 2024
8b773f6
Merge remote-tracking branch 'origin/heroku' into siyi
Blankeeir Aug 12, 2024
e254b1d
update python 3
Blankeeir Aug 12, 2024
ba2d920
update urls of contacts
Blankeeir Aug 13, 2024
87f60dd
update contact form
Blankeeir Aug 13, 2024
3d504da
Update settings.py
Blankeeir Aug 13, 2024
8f78a38
Update views.py
Blankeeir Aug 13, 2024
eb9a95c
Update urls.py
Blankeeir Aug 13, 2024
8713ff5
Fix publicity management page to follow notion
JasonRay168 Aug 22, 2024
a87994b
Merge pull request #29 from nussucommit/jason-ray/publicity-management
JasonRay168 Aug 22, 2024
2977fe4
Update .gitignore
papataco14 Aug 25, 2024
18cc2f3
Fix recursive parsing in Notion API handler
papataco14 Aug 25, 2024
6d3469e
Merge branch 'heroku' into siyi
Blankeeir Aug 27, 2024
847d533
Merge pull request #33 from nussucommit/rithik/data-view
JasonRay168 Aug 27, 2024
5e2f476
update virtual environment
Blankeeir Aug 27, 2024
defd684
update settings
Blankeeir Aug 27, 2024
0dde281
Make DEBUG an environment variable
JasonRay168 Aug 27, 2024
4a2f94e
Merge pull request #34 from nussucommit/jason-ray/heroku-config
JasonRay168 Aug 27, 2024
486c843
Update .gitignore
Blankeeir Aug 27, 2024
53fda7c
Update .gitignore
Blankeeir Aug 27, 2024
4f53ae3
Delete venv
JasonRay168 Sep 7, 2024
627d3f3
Update gitignore to ignore .DS_Store files
JasonRay168 Dec 8, 2024
2d246a6
Merge branch 'heroku' into siyi
JasonRay168 Dec 8, 2024
e8fe329
Edit settings to fix email host
JasonRay168 Dec 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
File renamed without changes.
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
*.txt
.env
__pycache__/
__pycache__/
backend/staticfiles/
.venv/
venv/
.DS_Store
2 changes: 2 additions & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
release: python manage.py migrate
web: gunicorn backend.wsgi --workers=3 --threads=6
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions backend/aboutus/urls.py → aboutus/urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django.urls import path
from django.urls import path, include
from aboutus import views

urlpatterns = [
path('aboutus/', views.aboutus),
path('history/', views.history),
path('governance/', views.governance),
path('ourteam/', views.ourteam),
path('ourteam/', include('ourteam.urls')),
path('president/', views.president),
]
10 changes: 5 additions & 5 deletions backend/aboutus/views.py → aboutus/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ def governance(request):
data = get_parsed_data(GOVERNANCE_URL)
return Response(data, status=status.HTTP_200_OK)

@api_view(['Get'])
def ourteam(request):
OUR_TEAM_URL = 'd64ee576792d48a4a3bbca2153795348'
data = get_parsed_data(OUR_TEAM_URL)
return Response(data, status=status.HTTP_200_OK)
# @api_view(['Get'])
# def ourteam(request):
# OUR_TEAM_URL = 'd64ee576792d48a4a3bbca2153795348'
# data = get_parsed_data(OUR_TEAM_URL)
# return Response(data, status=status.HTTP_200_OK)

@api_view(['Get'])
def president(request):
Expand Down
Binary file added backend/.DS_Store
Binary file not shown.
File renamed without changes.
File renamed without changes.
Binary file removed backend/backend/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file removed backend/backend/__pycache__/settings.cpython-39.pyc
Binary file not shown.
Binary file removed backend/backend/__pycache__/urls.cpython-39.pyc
Binary file not shown.
Binary file removed backend/backend/__pycache__/wsgi.cpython-39.pyc
Binary file not shown.
40 changes: 36 additions & 4 deletions backend/backend/settings.py → backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,38 @@
from dotenv import load_dotenv
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/

#Load Secret Key
load_dotenv()

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
STATICFILES_DIRS = [
os.path.join(PROJECT_ROOT, 'static'),
]

# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv("DJANGOSECRETKEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = True if os.getenv("DEBUG").lower() == 'true' else False

ALLOWED_HOSTS = ['*']

CORS_ALLOWED_ORIGINS = ["http://localhost:3000", "http://127.0.0.1:3000"]
CORS_ALLOWED_ORIGINS = ["http://localhost:3000", "http://127.0.0.1:3000", "https://kaleidoscopic-druid-8d4af7.netlify.app", "https://nussu.org.sg"]

# Application definition

Expand All @@ -42,9 +56,13 @@
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
# Disable Django's own staticfiles handling in favour of WhiteNoise, for
# greater consistency between gunicorn and `./manage.py runserver`. See:
# http://whitenoise.evans.io/en/stable/django.html#using-whitenoise-in-development
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -130,3 +148,17 @@
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'






# settings.py

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") # Note: Store credentials securely
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions backend/contact/urls.py → contact/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

urlpatterns = [
path('', views.contact),
path('submit_feedback/', views.submit_feedback, name='submit_feedback'),
]
85 changes: 85 additions & 0 deletions contact/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from django.core.mail import send_mail
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator
from dotenv import load_dotenv
from pathlib import Path
import os
import requests
from notionConnection.parser import parse


dotenv_path = Path('backend/.env')
load_dotenv(dotenv_path)
token = os.getenv('NOTION_API_KEY')
version = '2021-08-16'

NOTION_PAGE_URL = 'https://api.notion.com/v1/blocks/{blockid}/children'
NOTION_HEADER = {'Notion-Version': version, 'Authorization': token}



@api_view(['POST'])
def submit_feedback(request):
# Extract data from the request
sheet1 = request.data.get('sheet1', {})
full_name = sheet1.get('fullName')
email = sheet1.get('email')
subject = sheet1.get('subject')
question = sheet1.get('question')

# Validate the input
if not (full_name and email and subject and question):
return Response({"error": "Missing required fields"}, status=status.HTTP_400_BAD_REQUEST)


# Validate email format
email_validator = EmailValidator()
try:
email_validator(email)
except ValidationError:
return Response({"error": "Invalid email address"}, status=status.HTTP_400_BAD_REQUEST)

# Email configuration
SENDER_EMAIL = os.getenv('EMAIL_HOST_USER')
RECEIVER_EMAIL = SENDER_EMAIL # Feedback goes to the company email

# Send the feedback email
try:
send_mail(
subject=f"Feedback: {subject} from {full_name}",
message=f"Name: {full_name}\nEmail: {email}\nSubject: {subject}\nQuestion: {question}",
from_email=SENDER_EMAIL,
recipient_list=["emmaxu2005@gmail.com", "e1300538@u.nus.edu", "xusiyi2005@gmail.com"],
)
except Exception as e:
return Response({"error": "Failed to send feedback email", "details": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

# Send auto-reply to the user
try:
send_mail(
subject='Auto Reply From NUS Student Union',
message='Thank you for your message. We will get back to you soon.',
from_email=SENDER_EMAIL,
recipient_list=[email],
)

except Exception as e:
return Response({"error": "Failed to send auto reply", "details": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

return Response({"success": "Feedback submitted successfully"}, status=status.HTTP_200_OK)


@api_view(['Get'])
def contact(request):
CONTACT_URL = '80fc40185db84c88bd30824a10add0de'
data = get_parsed_data(CONTACT_URL)
return Response(data, status=status.HTTP_200_OK)

def get_parsed_data(id):
url = NOTION_PAGE_URL.format(blockid=id)
response = requests.get(url, headers=NOTION_HEADER)
data = response.json()
return parse(data)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion backend/home/urls.py → home/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
from home import views

urlpatterns = [
path('home/', views.home),
path('', views.home),
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
55 changes: 33 additions & 22 deletions backend/notionConnection/parser.py → notionConnection/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@

dotenv_path = Path('backend/.env')
load_dotenv(dotenv_path)
token = os.getenv('token')
version = os.getenv('version')
token = os.getenv('NOTION_API_KEY')
version = os.getenv('VERSION')

def parse(data):
if (data["object"] == "list"):
return parse_list(data["results"])
if isinstance(data, list):
return parse_list(data)

if isinstance(data, dict) and data.get("object") == "list":
return parse_list(data.get("results", []))

def parse_list(data):
list = []
Expand Down Expand Up @@ -40,27 +43,32 @@ def parse_numbered_list_item(data):
list = []
result["type"] = "numbered_list_item"
for i in data["numbered_list_item"]["text"]:
if (i["plain_text"] != ""):
if i["plain_text"]:
list.append(parse_text(i))
result["type"] = "numbered_list_item"

# Handle children recursively (similar to bulleted list items)
if data.get("has_children"):
url = 'https://api.notion.com/v1/blocks/' + data["id"] + '/children'
headers = {'Notion-Version': version, 'Authorization': f'Bearer {token}'}
response = requests.get(url, headers=headers)
response_data = response.json()

result["children"] = parse(response_data)

result["content"] = list
return result

def parse_heading(data):
result = dict()
result["type"] = "heading"

# quick and dirty fix for notion's buggy API being returned for events page
textArray = data[data["type"]]["text"]
for i in range(len(textArray)):
if textArray[i]["plain_text"] != "":
result["content"] = textArray[i]["plain_text"]
break

# result["content"] = data[data["type"]]["text"][0]["plain_text"]
return result


def parse_paragraph(data):
list = []
for i in data["paragraph"]["text"]:
Expand All @@ -80,13 +88,13 @@ def parse_text(data):
for attribute in data["annotations"]:
if (attribute != "color" and data["annotations"][attribute] == True):
special_attribute[attribute] = True

elif (attribute == "color" and data["annotations"][attribute] != "default"):
special_attribute[attribute] = data["annotations"][attribute]

if (data["text"]["link"]):
special_attribute["link"] = data["text"]["link"]["url"]
if (data["text"].get("link")):
special_attribute["link"] = data["text"]["link"]["url"]

result["annotations"] = special_attribute
return result

def parse_quote(data):
Expand All @@ -106,24 +114,29 @@ def parse_bullet_list(data):
list = []
for i in data["bulleted_list_item"]["text"]:
bullet_item = parse_text(i)

# Handle children recursively
if data["has_children"]:
url = 'https://api.notion.com/v1/blocks/' + data["id"] + '/children'
headers = {'Notion-Version': version, 'Authorization': token}
headers = {'Notion-Version': version, 'Authorization': f'Bearer {token}'}
response = requests.get(url, headers=headers)
responseData = response.json()
bullet_item["children"] = parse(responseData)

response_data = response.json()

# Recursively parse the children
bullet_item["children"] = parse(response_data)

list.append(bullet_item)

result["content"] = list
return result

def parse_table(data):
result = dict()
url = 'https://api.notion.com/v1/blocks/' + data["id"] + '/children'
headers = {'Notion-Version': version, 'Authorization': token}
headers = {'Notion-Version': version, 'Authorization': f'Bearer {token}'}
response = requests.get(url, headers=headers)
table = response.json()
#Assume that table does not have children inside the block

list = []
if "results" in table:
for i in table["results"]:
Expand All @@ -145,10 +158,8 @@ def parse_file(data):
result = dict()
result["type"] = "file"

# can be external of file type
type = data["file"]["type"]

if (type == "external"):
if type == "external":
result["url"] = data["file"]["external"]["url"]
else:
result["url"] = data["file"]["file"]["url"]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions ourteam/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class OurteamConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'ourteam'
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions ourteam/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.urls import path
from ourteam import views

urlpatterns = [
path('presidential/', views.presidential),
path('relations/', views.relations),
path('secretariat/', views.secretariat),
path('finance/', views.finance),
path('communications/', views.communications),
path('studentlife/', views.studentlife),
path('studentwelfare/', views.studentwelfare),
]
Loading