Skip to content

Commit

Permalink
Complete crud (#47)
Browse files Browse the repository at this point in the history
* delete student works

* styled buttons and stuff for student

* beautified student and parent pages

* delete instructor works now

* added delete to announcements and styled buttons

* Added delete buttons for class and styling

* fixed margin styling
  • Loading branch information
APandamonium1 authored Sep 25, 2024
1 parent ec2a555 commit 8c87800
Show file tree
Hide file tree
Showing 8 changed files with 484 additions and 132 deletions.
Binary file modified EduSync.exe
Binary file not shown.
110 changes: 110 additions & 0 deletions adminHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,30 @@ func AdminHandler(router *mux.Router) {
}
}).Methods("POST")

// Handle student deletion
router.HandleFunc("/admin/student/delete/{googleID}", func(res http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
googleID := vars["googleID"]

if req.Method == http.MethodDelete {
student, err := readStudent(googleID, req)
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

if err := deleteStudent(student, req); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

res.WriteHeader(http.StatusNoContent) // Respond with No Content status
return
}

http.Error(res, "Method Not Allowed", http.StatusMethodNotAllowed)
}).Methods("DELETE")

// Serve the search parent page
router.HandleFunc("/admin/search_parent", func(res http.ResponseWriter, req *http.Request) {
t, err := template.ParseFiles("templates/admin/search_parent.html")
Expand Down Expand Up @@ -266,6 +290,30 @@ func AdminHandler(router *mux.Router) {
}
}).Methods("POST")

// Handle parent deletion
router.HandleFunc("/admin/parent/delete/{googleID}", func(res http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
googleID := vars["googleID"]

if req.Method == http.MethodDelete {
parent, err := readParent(googleID, req)
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

if err := deleteParent(parent, req); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

res.WriteHeader(http.StatusNoContent) // Respond with No Content status
return
}

http.Error(res, "Method Not Allowed", http.StatusMethodNotAllowed)
}).Methods("DELETE")

// Serve the search instructor page
router.HandleFunc("/admin/search_instructor", func(res http.ResponseWriter, req *http.Request) {
t, err := template.ParseFiles("templates/admin/search_instructor.html")
Expand Down Expand Up @@ -377,6 +425,30 @@ func AdminHandler(router *mux.Router) {
t.Execute(res, nil)
}).Methods("GET")

// Handle instructor deletion
router.HandleFunc("/admin/instructor/delete/{googleID}", func(res http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
googleID := vars["googleID"]

if req.Method == http.MethodDelete {
instructor, err := readInstructor(googleID, req)
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

if err := deleteInstructor(instructor, req); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

res.WriteHeader(http.StatusNoContent) // Respond with No Content status
return
}

http.Error(res, "Method Not Allowed", http.StatusMethodNotAllowed)
}).Methods("DELETE")

// Serve the create announcement page
router.HandleFunc("/admin/create_announcement", func(res http.ResponseWriter, req *http.Request) {
t, err := template.ParseFiles("templates/admin/create_announcement.html")
Expand Down Expand Up @@ -473,6 +545,23 @@ func AdminHandler(router *mux.Router) {
// Request Body: JSON object with announcement details
// Response: HTTP Status Created (201)

// Handle announcement deletion
router.HandleFunc("/admin/announcement/delete/{announcementID}", func(res http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
announcementID := vars["announcementID"]

switch req.Method {
case http.MethodDelete:
if err := deleteAnnouncement(announcementID, req); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}
res.WriteHeader(http.StatusNoContent)
default:
http.Error(res, "Method Not Allowed", http.StatusMethodNotAllowed)
}
}).Methods("DELETE")

// Serve the search class page
router.HandleFunc("/admin/search_class", func(res http.ResponseWriter, req *http.Request) {
t, err := template.ParseFiles("templates/admin/search_class.html")
Expand Down Expand Up @@ -589,6 +678,27 @@ func AdminHandler(router *mux.Router) {
}
}).Methods("POST")

// Handle class deletion
router.HandleFunc("/admin/class/delete/{classID}", func(res http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
classID := vars["classID"]

switch req.Method {
case http.MethodDelete:
// Create a Class struct with the classID
class := Class{ClassID: classID}

// Call deleteClass function to delete the class
if err := deleteClass(class, req); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}
res.WriteHeader(http.StatusNoContent)
default:
http.Error(res, "Method Not Allowed", http.StatusMethodNotAllowed)
}
}).Methods("DELETE")

router.HandleFunc("/admin/api/profile", func(res http.ResponseWriter, req *http.Request) {
currentUser, err := GetCurrentUser(req)
if err != nil {
Expand Down
9 changes: 4 additions & 5 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"log"
"net/http"

"os"
"strings"

Expand All @@ -18,10 +17,10 @@ import (
var firebaseClient *db.Client

func SessionCookie() (string, error) {
// sessionCookieStore := goDotEnvVariable("SESSION_COOKIE_STORE")
// if sessionCookieStore == "" {
// return sessionCookieStore, fmt.Errorf("SESSION_COOKIE_STORE is not set in the environment variables")
// }
// sessionCookieStore := goDotEnvVariable("SESSION_COOKIE_STORE")
// if sessionCookieStore == "" {
// return sessionCookieStore, fmt.Errorf("SESSION_COOKIE_STORE is not set in the environment variables")
// }

sessionCookieStore, found := os.LookupEnv("COOKIESTORE")
if !found {
Expand Down
123 changes: 83 additions & 40 deletions templates/admin/search_announcement.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,14 @@
<link rel="stylesheet" type="text/css" href="/assets/css/style.css">
<link href="https://fonts.googleapis.com/css?family=Raleway:400,500,600,700" rel="stylesheet">
<script>
/**
* Fetches announcements from the provided URL and displays them in the results div.
*
* @param {string} url - The URL from which to fetch announcements.
* @throws Will throw an error if the fetch request fails.
*/
async function fetchAnnouncements(url) {
const response = await fetch(url);

if (!response.ok) {
const errorMessage = `Error: ${response.status} - ${response.statusText}`;
throw new Error(errorMessage);
}

const announcements = await response.json();
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
Expand All @@ -31,45 +25,56 @@
announcements.forEach(announcement => {
const announcementDiv = document.createElement('div');
announcementDiv.className = 'announcement';
announcementDiv.innerHTML = `<a href="/admin/announcement/${announcement.announcement_id}/edit"><strong>${announcement.subject}</strong></a> - ${announcement.content}`;
announcementDiv.innerHTML = `
<div class="announcement-entry">
<a href="/admin/announcement/${announcement.announcement_id}/edit"><strong>${announcement.subject}</strong></a> - ${announcement.content}
<button class="delete-button" onclick="confirmDelete('${announcement.announcement_id}')">Delete</button>
</div>
`;
resultsDiv.appendChild(announcementDiv);
});
} else {
resultsDiv.innerHTML = 'No announcements found.';
}
}

/**
* Searches for announcements based on the subject filter and displays the results.
*/
async function searchAnnouncements() {
const subjectFilter = document.getElementById('subjectFilter').value;
const response = await fetch(`/admin/api/search_announcement?subject=${subjectFilter}`);

if (!response.ok) {
const errorMessage = `Error: ${response.status} - ${response.statusText}`;
throw new Error(errorMessage);
function confirmDelete(announcementID) {
if (confirm("Are you sure you want to delete this announcement?")) {
deleteAnnouncement(announcementID);
}

const announcements = await response.json();
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
}

if (announcements && announcements.length > 0) {
announcements.forEach(announcement => {
const announcementDiv = document.createElement('div');
announcementDiv.className = 'announcement';
announcementDiv.innerHTML = `<a href="/admin/announcement/${announcement.announcementID}"><strong>${announcement.subject}</strong></a> - ${announcement.content}`;
resultsDiv.appendChild(announcementDiv);
async function deleteAnnouncement(announcementID) {
try {
const response = await fetch(`/admin/announcement/delete/${announcementID}`, {
method: 'DELETE',
});
} else {
resultsDiv.innerHTML = 'No announcements found.';

if (response.ok) {
alert("Announcement deleted successfully.");
await searchAnnouncements(); // Refresh the list
} else {
const errorMessage = `Error: ${response.status} - ${response.statusText}`;
throw new Error(errorMessage);
}
} catch (error) {
alert(`Failed to delete announcement: ${error.message}`);
}
}

/**
* Fetches announcements when the page loads.
* Searches for announcements based on the subject filter and displays the results.
*/
async function searchAnnouncements() {
const titleFilter = document.getElementById('titleFilter').value;
await fetchAnnouncements(`/admin/api/search_announcement?title=${titleFilter}`);
}

async function resetFilters() {
document.getElementById('titleFilter').value = '';
await fetchAnnouncements(`/admin/api/search_announcement`);
}

window.onload = async function() {
await fetchAnnouncements(`/admin/api/search_announcement`);
}
Expand All @@ -87,8 +92,40 @@
text-decoration: underline; /* Add underline on hover (optional) */
}

.error-message {
color: red;
.delete-button {
background-color: #ff4d4d; /* Red background for delete button */
color: white; /* White text */
border: none; /* Remove default border */
padding: 5px 10px; /* Add padding */
margin-left: 10px; /* Space between button and other elements */
cursor: pointer; /* Pointer cursor on hover */
border-radius: 3px; /* Rounded corners */
}

.delete-button:hover {
background-color: #cc0000; /* Darker red on hover */
}

/* Other buttons with #246EB9 background */
.action-button {
background-color: #246EB9; /* Blue background */
color: white; /* White text */
border: none; /* Remove default border */
cursor: pointer; /* Pointer cursor on hover */
border-radius: 3px; /* Rounded corners */
}

.action-button:hover {
background-color: #1b5791; /* Darker blue on hover */
}

/* Add space between announcement entries */
.announcement-entry {
margin-bottom: 15px; /* Space between rows */
}

.announcement-entry a {
text-decoration: none; /* Remove underline from links */
}
</style>
</head>
Expand All @@ -98,8 +135,9 @@
<div class="main-header">
<div class="container">
<div class="logo-wrap" itemprop="logo">
<img src="/assets/images/site-logo.jpg" alt="Logo Image" style="width: 120px; height: auto;">
<!-- <h1>Education</h1> -->
<a href="/admin">
<img src="/assets/images/site-logo.jpg" alt="Logo Image" style="width: 120px; height: auto;">
</a>
</div>
<div class="nav-wrap">
<nav class="nav-desktop">
Expand All @@ -111,6 +149,7 @@
<li><a href="/admin/search_announcement">Announcements</a></li>
<li><a href="/admin/search_class">Classes</a></li>
<li><a href="/admin/profile">Profile</a></li>
<li><a href="/logout">Logout</a></li>
</ul>
</nav>
<div id="bar">
Expand All @@ -131,10 +170,14 @@
<h1>Search Announcements</h1>
<br>
<div>
<label for="subjectFilter">subject:</label>
<input type="text" id="subjectFilter">
<button onclick="searchAnnouncements()">Search</button>
<button onclick="window.location.href='/admin/create_announcement'">Create</button>
<label for="titleFilter">Title:</label>
<input type="text" id="titleFilter">
&nbsp;&nbsp;&nbsp;
<button class="action-button" onclick="searchAnnouncements()">Search</button>
&nbsp;
<button class="action-button" onclick="resetFilters()">Reset</button>
&nbsp;
<button class="action-button" onclick="window.location.href='/admin/create_announcement'">Create</button>
</div>
<br>
<div id="results"></div>
Expand All @@ -148,4 +191,4 @@ <h1>Search Announcements</h1>
<script type="text/javascript" src="/assets/js/jquery.rateyo.js"></script>
<script type="text/javascript" src="/assets/js/custom.js"></script>
</body>
</html>
</html>
Loading

0 comments on commit 8c87800

Please sign in to comment.