From d12bbbd8a9f0e919387085af634479cf9552b7d8 Mon Sep 17 00:00:00 2001
From: James2Tulloch <146088090+James2Tulloch@users.noreply.github.com>
Date: Thu, 6 Mar 2025 13:16:51 +0000
Subject: [PATCH] Working groups iterator, needs frontend work

---
 .../myapp/templates/myapp/base.html           | 15 +++----
 .../myapp/templates/myapp/group_create.html   |  2 +-
 .../myapp/templates/myapp/group_list.html     | 28 +++++++------
 django_project/myapp/views/groupviews.py      | 12 ++++++
 rust_crud_api/src/db/groups.rs                | 40 +++++++++++++------
 rust_crud_api/src/db/init.rs                  |  3 +-
 rust_crud_api/src/models/group.rs             |  3 ++
 7 files changed, 70 insertions(+), 33 deletions(-)

diff --git a/django_project/myapp/templates/myapp/base.html b/django_project/myapp/templates/myapp/base.html
index e1e4c4e..e8b3af8 100644
--- a/django_project/myapp/templates/myapp/base.html
+++ b/django_project/myapp/templates/myapp/base.html
@@ -26,6 +26,10 @@
         nav li a:hover {
             background-color: #111;
         }
+        nav form {
+            float: right;
+            margin: 10px;
+        }
         .container {
             margin: 20px;
         }
@@ -40,15 +44,12 @@
             <li><a href="{% url 'account' %}">Account</a></li>
             <li><a href="{% url 'group_list' %}">Groups</a></li>
             <li><a href="{% url 'logout' %}">Logout</a></li>
-            
+            <form method="GET" action="{% url 'group_search' %}">
+                <input type="text" name="q" placeholder="Search for groups..." value="{{ search_query }}">
+                <button type="submit">Search</button>
+            </form>   
         </ul>
-
-        <form method="GET" action="{% url 'group_search' %}">
-            <input type="text" name="q" placeholder="Search for groups..." value="{{ search_query }}">
-            <button type="submit">Search</button>
-        </form>
     </nav>
-
     <!-- Page Content -->
     <div class="container">
         {% block content %}
diff --git a/django_project/myapp/templates/myapp/group_create.html b/django_project/myapp/templates/myapp/group_create.html
index d1a52b6..3017595 100644
--- a/django_project/myapp/templates/myapp/group_create.html
+++ b/django_project/myapp/templates/myapp/group_create.html
@@ -17,6 +17,6 @@
         <button type="submit">Create Group</button>
     </form>
     <p><a href="{% url 'group_list' %}">Back to Group List</a></p>
-</body>
+</body> 
 </html>
 
diff --git a/django_project/myapp/templates/myapp/group_list.html b/django_project/myapp/templates/myapp/group_list.html
index 9f1d94d..9c012dc 100644
--- a/django_project/myapp/templates/myapp/group_list.html
+++ b/django_project/myapp/templates/myapp/group_list.html
@@ -4,17 +4,21 @@
 
 {% block content %}
   <h1>Groups</h1>
-    {% if error %}
-        <p style="color: red;">{{ error }}</p>
-    {% endif %}
-    <ul>
-        {% for group in groups %}
-            <li>
-                <a href="{% url 'group_detail' group.id %}">{{ group.name }}</a>
-            </li>
-        {% empty %}
-            <li>No groups available.</li>
-        {% endfor %}
-    </ul>
+  
+  {% if error %}
+      <p style="color: red;">{{ error }}</p>
+  {% endif %}
+  
+  <ul>
+      {% for group in groups %}
+          <li>
+              <!-- Hyperlinked Group Name -->
+              <a href="{% url 'group_detail' group.id %}">{{ group.name }}</a> 
+    
+          </li>
+      {% empty %}
+          <li>No groups available.</li>
+      {% endfor %}
+  </ul>
 
 {% endblock %}
diff --git a/django_project/myapp/views/groupviews.py b/django_project/myapp/views/groupviews.py
index 4617d49..f73ac8a 100644
--- a/django_project/myapp/views/groupviews.py
+++ b/django_project/myapp/views/groupviews.py
@@ -100,15 +100,27 @@ def group_detail_view(request, group_id):
     """
     db_url = settings.DATABASE_URL
     context = {}
+
     try:
+        # Fetch group details
         group = rust_crud_api.get_group(db_url, group_id)
         if group is None:
             return HttpResponseNotFound("Group not found.")
+
+        # Fetch group members and member count
+        members, member_count = rust_crud_api.get_group_members(db_url, group_id)
+
+        # Populate context with group details
         context['group'] = group
+        context['members'] = members
+        context['member_count'] = member_count
+
     except Exception as e:
         context['error'] = f"An error occurred: {e}"
+
     return render(request, 'myapp/group_detail.html', context)
 
+
 def group_search_view(request):
     """
     Handles searching for groups using Rust.
diff --git a/rust_crud_api/src/db/groups.rs b/rust_crud_api/src/db/groups.rs
index d98d1f7..e553482 100644
--- a/rust_crud_api/src/db/groups.rs
+++ b/rust_crud_api/src/db/groups.rs
@@ -13,8 +13,8 @@ fn pg_err(e: postgres::Error) -> PyErr {
 pub fn create_group(db_url: &str, name: &str) -> PyResult<()> {
     let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?;
     client.execute(
-        "INSERT INTO groups (name) VALUES ($1)",
-        &[&name]
+        "INSERT INTO groups (name, member_count) VALUES ($1, $2)", // Use $2 for member_count
+        &[&name, &0]  // Pass 0 explicitly as an i32
     ).map_err(pg_err)?;
     Ok(())
 }
@@ -24,7 +24,7 @@ pub fn create_group(db_url: &str, name: &str) -> PyResult<()> {
 pub fn get_group(db_url: &str, group_id: i32) -> PyResult<Option<Group>> {
     let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?;
     let row_opt = client.query_opt(
-        "SELECT id, name FROM groups WHERE id = $1",
+        "SELECT id, name, member_count FROM groups WHERE id = $1",
         &[&group_id]
     ).map_err(pg_err)?;
     
@@ -32,6 +32,7 @@ pub fn get_group(db_url: &str, group_id: i32) -> PyResult<Option<Group>> {
         let group = Group {
             id: row.get(0),
             name: row.get(1),
+            member_count: row.get(2),
         };
         Ok(Some(group))
     } else {
@@ -43,12 +44,13 @@ pub fn get_group(db_url: &str, group_id: i32) -> PyResult<Option<Group>> {
 #[pyfunction]
 pub fn get_all_groups(db_url: &str) -> PyResult<Vec<Group>> {
     let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?;
-    let rows = client.query("SELECT id, name FROM groups", &[])
+    let rows = client.query("SELECT id, name, member_count FROM groups", &[])
         .map_err(pg_err)?;
     
     let groups = rows.into_iter().map(|row| Group {
         id: row.get(0),
         name: row.get(1),
+        member_count: row.get(2),
     }).collect();
     
     Ok(groups)
@@ -62,21 +64,27 @@ pub fn add_user_to_group(db_url: &str, group_id: i32, user_id: i32) -> PyResult<
         "INSERT INTO group_members (group_id, user_id) VALUES ($1, $2)",
         &[&group_id, &user_id]
     ).map_err(pg_err)?;
+    client.execute(
+        "UPDATE groups SET member_count = member_count + 1 WHERE id = $1",
+        &[&group_id]
+    ).map_err(pg_err)?;
     Ok(())
 }
 
 /// Get all members of a group.
 #[pyfunction]
-pub fn get_group_members(db_url: &str, group_id: i32) -> PyResult<Vec<User>> {
+pub fn get_group_members(db_url: &str, group_id: i32) -> PyResult<(Vec<User>, i32)> {
     let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?;
+
+    // Fetch group members
     let rows = client.query(
-        "SELECT u.id, u.name, u.email
+        "SELECT u.id, u.name, u.email, u.username, u.studentid, u.startyear, u.endyear, u.profilepicture, u.firstlogin
          FROM users u
          JOIN group_members gm ON u.id = gm.user_id
          WHERE gm.group_id = $1",
-         &[&group_id]
+        &[&group_id]
     ).map_err(pg_err)?;
-    
+
     let users = rows.into_iter().map(|row| User {
         id: row.get(0),
         name: row.get(1),
@@ -86,12 +94,19 @@ pub fn get_group_members(db_url: &str, group_id: i32) -> PyResult<Vec<User>> {
         startyear: row.get(5),
         endyear: row.get(6),
         profilepicture: row.get(7),
-        firstlogin: row.get(8)
+        firstlogin: row.get(8),
     }).collect();
-    
-    Ok(users)
+
+    // Fetch member count
+    let count: i32 = client.query_one(
+        "SELECT member_count FROM groups WHERE id = $1",
+        &[&group_id]
+    ).map_err(pg_err)?.get(0);
+
+    Ok((users, count))
 }
 
+
 /// Group Delete Function
 #[pyfunction]
 pub fn delete_group(db_url: &str, group_id: i32) -> PyResult<bool> {
@@ -107,7 +122,7 @@ pub fn delete_group(db_url: &str, group_id: i32) -> PyResult<bool> {
 pub fn search_groups(db_url: &str, query: &str) -> PyResult<Vec<Group>> {
     let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?;
     let rows = client.query(
-        "SELECT id, name FROM groups WHERE name ILIKE $1",
+        "SELECT id, name, member_count FROM groups WHERE name ILIKE $1",
         &[&format!("%{}%", query)] 
     ).map_err(pg_err)?;
 
@@ -115,6 +130,7 @@ pub fn search_groups(db_url: &str, query: &str) -> PyResult<Vec<Group>> {
         .map(|row| Group {
             id: Some(row.get(0)),
             name: row.get(1),
+            member_count: row.get(2),
         })
         .collect();
 
diff --git a/rust_crud_api/src/db/init.rs b/rust_crud_api/src/db/init.rs
index 045676d..9e090ac 100644
--- a/rust_crud_api/src/db/init.rs
+++ b/rust_crud_api/src/db/init.rs
@@ -25,7 +25,8 @@ pub fn init_db(db_url: &str) -> PyResult<()> {
         );
         CREATE TABLE IF NOT EXISTS groups (
             id SERIAL PRIMARY KEY,
-            name VARCHAR NOT NULL
+            name VARCHAR NOT NULL,
+            member_count INTEGER DEFAULT 0
         );
         CREATE TABLE IF NOT EXISTS group_members (
             group_id INTEGER REFERENCES groups(id),
diff --git a/rust_crud_api/src/models/group.rs b/rust_crud_api/src/models/group.rs
index ab2ebe3..c95423a 100644
--- a/rust_crud_api/src/models/group.rs
+++ b/rust_crud_api/src/models/group.rs
@@ -8,5 +8,8 @@ pub struct Group {
     pub id: Option<i32>,
     #[pyo3(get, set)]
     pub name: String,
+    #[pyo3(get, set)]
+    pub member_count: i32,
+    
 }
 
-- 
GitLab