diff --git a/django_project/myapp/templates/myapp/base.html b/django_project/myapp/templates/myapp/base.html index 3a284d81acf734f6ae17c5d3ba74a998d8a5d6bb..e5e79458d8d1251d0ed78889d315f960fda86da5 100644 --- a/django_project/myapp/templates/myapp/base.html +++ b/django_project/myapp/templates/myapp/base.html @@ -7,7 +7,6 @@ <style> nav { background-image: linear-gradient(to right, #00bfff, #00ffd5); - /*background-color: #344cff;*/ overflow: hidden; } nav ul { diff --git a/django_project/myapp/templates/myapp/group_detail.html b/django_project/myapp/templates/myapp/group_detail.html index faba797a3f7968a5301102b19854f40ce7d081d5..d34906382b2dfe0a6b1634b862d46e1bbacdb291 100644 --- a/django_project/myapp/templates/myapp/group_detail.html +++ b/django_project/myapp/templates/myapp/group_detail.html @@ -9,6 +9,16 @@ {% else %} <p><strong>Group Name:</strong> {{ group.name }}</p> <p><strong>Group ID:</strong> {{ group.id }}</p> + <p><strong>Member Count:</strong> {{ group.member_count }}</p> + {% if request.user in group.members.all %} + <p>You’re already a member of this group.</p> + {% else %} + <form method="post"> + {% csrf_token %} + <input type="hidden" name="user_id" value="{{ request.user.id }}"> + <button type="submit">Join Group</button> + </form> + {% endif %} {% endif %} <p><a href="{% url 'group_list' %}">Back to Groups</a></p> </body> diff --git a/django_project/myapp/templates/myapp/login.html b/django_project/myapp/templates/myapp/login.html index 235de7bce809ce9ad95a4c1a2f9d13746c295ca4..dd14de3d34faeaeac9ebd4eead55eaf033955ab5 100644 --- a/django_project/myapp/templates/myapp/login.html +++ b/django_project/myapp/templates/myapp/login.html @@ -4,29 +4,83 @@ <meta charset="UTF-8"> <title>Login</title> <style> - body { font-family: Arial, sans-serif; margin: 2em; } - .error { color: red; } + body { + font-family: Arial, sans-serif; + margin: 0; + display: flex; + height: 100vh; + } + .container { + display: flex; + width: 100%; + } + .left, .right { + width: 50%; + display: flex; + justify-content: center; + align-items: center; + padding: 2em; + } + .left { + background-color: #f8f9fa; + } + .right { + background-image: linear-gradient(to right, #00bfff, #00ffd5); + text-align: center; + } + .error { + color: red; + } + form { + width: 100%; + max-width: 300px; + } + input, button { + width: 100%; + padding: 0.5em; + margin-top: 0.5em; + } + button { + background-color: #007bff; + color: white; + border: none; + cursor: pointer; + } + button:hover { + background-color: #0056b3; + } </style> </head> <body> - <h1>Login</h1> - {% if error %} - <p class="error">{{ error }}</p> - {% endif %} - <form method="post"> - {% csrf_token %} - <label for="id_email">Email:</label> - <input type="email" name="email" id="id_email" required><br><br> - - <label for="id_password">Password:</label> - <input type="password" name="password" id="id_password" required><br><br> - - <button type="submit">Login</button> - </form> - <p> - Don't have an account? - <a href="{% url 'register' %}">Register here</a>. - </p> + <div class="container"> + <div class="left"> + <div> + <h1>Login</h1> + {% if error %} + <p class="error">{{ error }}</p> + {% endif %} + <form method="post"> + {% csrf_token %} + <label for="id_email">Email:</label> + <input type="email" name="email" id="id_email" required><br> + + <label for="id_password">Password:</label> + <input type="password" name="password" id="id_password" required><br> + + <button type="submit">Login</button> + </form> + <p> + Don't have an account? + <a href="{% url 'register' %}">Register here</a>. + </p> + </div> + </div> + <div class="right"> + <h1>UniHub</h1> + <p>Where university happens.</p> + </div> + </div> </body> </html> + diff --git a/django_project/myapp/views/groupviews.py b/django_project/myapp/views/groupviews.py index f73ac8a45f07274db93d13d722f4601c02de73aa..a4f28c956a6a2aae4b5bccb14c01eaca74b0076c 100644 --- a/django_project/myapp/views/groupviews.py +++ b/django_project/myapp/views/groupviews.py @@ -95,38 +95,36 @@ def group_delete_view(request, group_id): return render(request, 'myapp/group_delete.html', context) def group_detail_view(request, group_id): - """ - Fetch a single group's details using the Rust extension and display them. - """ 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) + if request.method == 'POST': + user_id = request.POST.get('user_id') # might be None or 'None' - # Populate context with group details - context['group'] = group - context['members'] = members - context['member_count'] = member_count + # Check for None *before* calling Rust + if not user_id or user_id == 'None': + context['error'] = "Invalid user_id: None" + return render(request, 'myapp/group_detail.html', context) - except Exception as e: - context['error'] = f"An error occurred: {e}" + try: + # Now we safely do int(user_id) because we checked it's not None + result = rust_crud_api.add_user_to_group(db_url, int(group_id), int(user_id)) + except Exception as e: + context['error'] = f"An error occurred: {e}" + return render(request, 'myapp/group_detail.html', context) + # Normal GET behavior... return render(request, 'myapp/group_detail.html', context) + + def group_search_view(request): """ Handles searching for groups using Rust. """ db_url = settings.DATABASE_URL - query = request.GET.get("q", "").strip() + query = request .GET.get("q", "").strip() groups = [] if query: try: @@ -135,4 +133,3 @@ def group_search_view(request): return render(request, "group_search.html", {"error": str(e), "query": query}) return render(request, "group_search.html", {"groups": groups, "query": query}) - diff --git a/rust_crud_api/src/models/events.rs b/rust_crud_api/src/db/events.rs similarity index 100% rename from rust_crud_api/src/models/events.rs rename to rust_crud_api/src/db/events.rs diff --git a/rust_crud_api/src/db/groups.rs b/rust_crud_api/src/db/groups.rs index fa9e5a967482dccba4d268be7f0bc698aa263f52..27f6d68a5ba95eb590dd5cdea644023b0dff313f 100644 --- a/rust_crud_api/src/db/groups.rs +++ b/rust_crud_api/src/db/groups.rs @@ -60,17 +60,19 @@ pub fn get_all_groups(db_url: &str) -> PyResult<Vec<Group>> { #[pyfunction] pub fn add_user_to_group(db_url: &str, group_id: i32, user_id: i32) -> PyResult<()> { let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?; + + // Insert a row to show membership client.execute( - "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] + "INSERT INTO group_members (group_id, user_id) + VALUES ($1, $2) + ON CONFLICT DO NOTHING", + &[&group_id, &user_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>, i32)> { @@ -134,3 +136,13 @@ pub fn search_groups(db_url: &str, query: &str) -> PyResult<Vec<Group>> { Ok(groups) } + +#[pyfunction] +pub fn get_group_member_count(db_url: &str, group_id: i32) -> PyResult<i64> { + let mut client = Client::connect(db_url, NoTls).map_err(pg_err)?; + let row = client.query_one( + "SELECT COUNT(*) FROM group_members WHERE group_id = $1", + &[&group_id] + ).map_err(pg_err)?; + Ok(row.get(0)) // returns i64 +} \ No newline at end of file diff --git a/rust_crud_api/src/db/init.rs b/rust_crud_api/src/db/init.rs index 377bcdb2d99f04c4d8927f36e38131e3d45f5b0f..d6c4ae201836cf601efd6cc593a66f3f660755e6 100644 --- a/rust_crud_api/src/db/init.rs +++ b/rust_crud_api/src/db/init.rs @@ -27,7 +27,7 @@ pub fn init_db(db_url: &str) -> PyResult<()> { CREATE TABLE IF NOT EXISTS groups ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL, - member_count INTEGER DEFAULT 0 + member_count INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS group_members (