Compare commits

...

53 Commits

Author SHA1 Message Date
mrlan 246565c8e9 Merge pull request 'Aya's writing on how to install LRR and how to run regression test' (#74) from InstallationGuide into Hui-Organize
Reviewed-on: #74
2025-07-10 16:01:06 +08:00
mrlan b37955daa8 Merge pull request 'Fix Bug48: Implememt Password Recovery Using Security Questions' (#73) from Bug48-Aya into Hui-Organize
Reviewed-on: #73
2025-07-10 16:00:18 +08:00
Lan Hui 4e0d97afb4 Add back file types to be ignored 2025-07-10 15:57:41 +08:00
Lan Hui b0a44c001d Use teacher's config for date and time 2025-07-10 15:56:41 +08:00
Lan Hui f6833e7398 Use teacher's DB password 2025-07-10 15:52:07 +08:00
Lan Hui 2ce0aa95b2 Helper function logout() does not work anymore with the new SecurityQuestions page. So use URL instead. 2025-05-20 07:46:33 +08:00
Lan Hui 43e9cfeffe Put every doc in the folder doc/ 2025-05-20 06:56:48 +08:00
Lan Hui b264ce4299 Aya's writing on how to install LRR and how to run regression test 2025-05-20 06:50:21 +08:00
Aya Boussouf a86c810a2d Update signup redirection to SecurityQuestions.php 2025-05-17 18:38:25 +00:00
Aya Boussouf 8876825ef9 Fix Bug48: Implememt Password Recovery Using Security Questions 2025-05-14 17:43:36 +00:00
Lan Hui 21918cf883 Extend assignment due date so that it can pass my tests 2025-02-22 10:08:41 +08:00
Lan Hui 62966c82fa Script.php: remove RESET Password stuff because there is no form with ID 'form_reset_password' 2024-10-26 09:46:29 +08:00
Lan Hui bc77fa1aa4 Update starter DB data so that the course_sutdents_table contains duplicate student-course info. 2024-10-26 09:38:44 +08:00
Lan Hui 9a4a8d2818 Courses.php: Fix Bug 36 2024-10-26 09:32:16 +08:00
Lan Hui 07ba57eebb Fix bug 195. 2024-10-10 15:35:00 +08:00
Lan Hui 1f602e3db2 Fix bug 204: use better parameter name. 2024-10-08 09:41:45 +08:00
Lan Hui 5ce55c3f1e Fix bug 204 2024-10-08 09:34:09 +08:00
Lan Hui 9d170fea87 Fix bug 484 2024-10-07 07:52:22 +08:00
Lan Hui 0f42a68461 Fix bug 558 2024-10-06 09:39:58 +08:00
Lan Hui e8bbce386a More informative message when no search result is returned 2024-10-05 07:43:10 +08:00
Lan Hui 545915b8be Stay on the same tab after creating a new TA account 2024-10-04 09:07:40 +08:00
Lan Hui aa82e9b5db Add one new regression test: test_student_with_weak_password_cannot_sign_up 2024-10-02 11:09:07 +08:00
Lan Hui 0a12b69d2c Show Chinese characters properly (related to Bug 200) 2024-10-02 10:30:46 +08:00
Lan Hui 54cb51d3a6 Add one new regression test: test_lecturer_can_mark_assignment (revised) 2024-10-01 14:40:58 +08:00
Lan Hui 5cef5875f6 Add one new regression test: test_lecturer_can_mark_assignment 2024-10-01 11:51:36 +08:00
Lan Hui 5e1cfcbbcc Add 2 new regression tests: test_student_can_submit_assignment & test_student_can_request_remarking 2024-09-30 16:16:03 +08:00
Lan Hui 44aa38be76 Add a new regression test: test_student_can_join_course 2024-09-28 09:46:52 +08:00
Lan Hui debd85e74d Add two new regression tests: test_student_with_valid_student_number_can_sign_up, test_student_with_invalid_student_number_cannot_sign_up 2024-09-27 10:16:01 +08:00
Lan Hui 39c14f7425 Add a new regression test: test_lecturer_can_add_student_numbers 2024-09-26 18:14:37 +08:00
Lan Hui 1ed7e2e394 Add test case: test_lecturer_can_post_assignment 2024-09-25 16:10:55 +08:00
Lan Hui a34ab61916 Add a new regression test 2024-09-24 09:09:54 +08:00
Lan Hui 33f997412b Improve the test script 2024-09-22 11:28:02 +08:00
Lan Hui b1dbd94b00 Add a regression test script and fix bug 2024-09-22 10:50:49 +08:00
Lan Hui 7388868678 README.md: edit 2024-09-17 14:58:47 +08:00
Lan Hui aa85b742f5 README.md: how to restore database 2024-09-17 14:51:22 +08:00
Lan Hui e1c95395ef README.md: seperate Q and A into two different lines 2024-09-17 14:40:23 +08:00
mrlan 65920bc0ac Merge pull request 'Fix bug 193 http://118.25.96.118/bugzilla/show_bug.cgi?id=193' (#35) from Bug193-Martha into Hui-Organize
Reviewed-on: #35
2024-09-16 19:25:29 +08:00
Lan Hui e66af1f419 Fix Bug 193 2024-09-16 19:22:39 +08:00
mrlan 162b347119 Merge pull request 'BUG430-Eden test script' (#70) from Eden-Testscript into Hui-Organize
Reviewed-on: #70
2024-09-16 18:47:01 +08:00
mrlan 5ebb0ccd6c Merge pull request 'Fix Bug 430' (#63) from Bug430-Eden into Hui-Organize
Reviewed-on: #63
2024-09-15 16:03:59 +08:00
Lan Hui 5bbd812189 Fix bug 430 2024-09-15 16:02:40 +08:00
Lan Hui 162de63b4d Merge branch 'Bug430-Eden' of http://118.25.96.118:3000/mrlan/LRR into Bug430-Eden 2024-09-15 15:45:20 +08:00
mrlan 88d20ed476 Merge pull request 'Bug486-Nartey' (#65) from Bug486-Nartey into Hui-Organize
Reviewed-on: #65
2024-09-15 15:34:57 +08:00
Lan Hui 5d0d0d91f7 Resolve merge conflict 2024-09-15 15:32:30 +08:00
mrlan fea32072c3 Merge pull request 'Bug352-Neil-Revised' (#69) from Bug352-Neil-Revised into Hui-Organize
Reviewed-on: #69
2024-09-15 14:23:42 +08:00
nartey 5639ce4c6b test script 2024-06-21 13:32:50 +08:00
nartey 8f3919d3bb TestScript 2024-06-21 13:16:11 +08:00
ADMASU EDEN SOLOMON da18cb617d BUG430-Eden test script 2024-06-21 06:06:32 +08:00
ADMASU EDEN SOLOMON 64ffc3af1c Resolve merge conflict( probably due to overlapping changes made in branch Bug557-Ayoub 2024-01-12 02:24:45 +08:00
Nartey Sylvester Amanor 9f03d380cd Fix Bug486 2023-12-31 19:43:47 +08:00
Nartey Sylvester Amanor c1f95ce017 Bug Fix 486 2023-12-31 18:20:22 +08:00
ADMASU EDEN SOLOMON adc9daef98 Fix Bug 430 2023-12-27 03:15:49 +08:00
Lan Hui fc8ad0c0a9 Fix bug 193 http://118.25.96.118/bugzilla/show_bug.cgi?id=193 2022-03-23 14:57:05 +08:00
24 changed files with 1496 additions and 117 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
.vscode
.DS_Store
venv/
__pycache__/
*.pyc

View File

@ -30,7 +30,7 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
<ul class="nav nav-tabs" id="myTab">
<li class="nav-item">
<a class="nav-link active" href="#tab-student-accounts" id="batch_tab">Create student accounts</a>
<a class="nav-link active" href="#tab-student-accounts" id="batch_tab">Enter student numbers</a>
</li>
<li class="nav-item">
@ -66,7 +66,7 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
?>
<form method="post" action="Script.php" id="create_account_form">
<input type="hidden" name="form_createlecturrer" value="true" required="" />
<input type="hidden" name="form_createlecturer" value="true" required="" />
Full name
<input type="text" name="fullname" placeholder="Full Name" class="form-control" required=""> <br>
Email
@ -93,10 +93,6 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
echo '<hr><div class="alert alert-warning" role="alert">' . $_SESSION['info_Admin_Users'] . '</div>';
$_SESSION['info_Admin_Users'] = null;
}
if (isset($_SESSION['info_Admin_Users'])) {
echo '<hr><div class="alert alert-warning" role="alert">' . $_SESSION['info_Admin_Users'] . '</div>';
$_SESSION['info_Admin_Users'] = null;
}
?>
</form>
@ -117,10 +113,21 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
<?php
if ($_SESSION['user_type'] == "Lecturer") {
$user_id = $_SESSION['user_id'];
echo "<script>console.log('here {$user_id}');</script>"; // debug trick
// find the TAs in the courses taught by this instructor
$ta_result = mysqli_query(
$con,
"SELECT TA FROM course_ta INNER JOIN courses_table ON course_ta.Course_ID=courses_table.Course_ID WHERE courses_table.Lecturer_User_ID=$user_id"
);
$ta_ids = array(-1); // -1 is non-existent ID
while ($row = mysqli_fetch_assoc($ta_result)) {
array_push($ta_ids, $row['TA']);
}
$ta_ids2 = implode(', ', $ta_ids);
$result = mysqli_query(
$con,
"SELECT * FROM users_table WHERE UserType in ('TA')"
"SELECT * FROM users_table WHERE UserType in ('TA') and User_ID in ($ta_ids2)"
);
}
@ -131,6 +138,7 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
);
}
$num_rows = 0;
while ($row = mysqli_fetch_assoc($result)) {
$pass = $row['Password'];
$btn = "<button class='btn btn-warning' onclick=\"updatePassword(" . $row['User_ID'] . ",'$pass')\">Reset</button>";
@ -143,6 +151,10 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
}
echo "<tr><td>" . $row['User_ID'] . "</td><td>" . $row['Full_Name'] . "</td><td>" . $row['Email'] . "</td><td>$btn</td><td>$btnBlock</td></tr>";
$num_rows += 1;
}
if ($num_rows == 0) {
echo "<p>No TA</p>";
}
?>
</table>
@ -227,8 +239,22 @@ if ($_SESSION['user_type'] != "Lecturer" && $_SESSION['user_type'] != "Admin") {
</div>
<?php include 'Footer.php';?>
<script>
/** After creating a TA account, stay on the same tab "Create instructor account"
Side effect: ?tacreated will be appended on the URL
*/
document.addEventListener("DOMContentLoaded", () => {
const url = new URL(window.location.href);
if (url.searchParams.has('tacreated')) {
const elem = document.querySelector('#tab_ins_accounts');
elem.click();
}
});
</script>
<script>
function updatePassword(id, pass) {
if (!confirm('Are you sure to reset user password?')) {

View File

@ -0,0 +1,87 @@
<?php
include 'NoDirectPhpAcess.php';
include 'Header.php';
include "get_mysql_credentials.php"; // Database credentials
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Connect to the database
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
if (mysqli_connect_errno()) {
die("Connection failed: " . mysqli_connect_error());
}
// Check if user is logged in
if (isset($_SESSION['email'])) {
$email = $_SESSION['email'];
// Check if form is submitted
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Get the submitted answers
$answer1 = strtolower(trim($_POST['answer1']));
$answer2 = strtolower(trim($_POST['answer2']));
// Fetch correct answers from the database
$sql = "SELECT user_id, answer1, answer2 FROM password_recovery_security_questions WHERE email = '$email'";
$result = mysqli_query($con, $sql);
if ($row = mysqli_fetch_assoc($result)) {
// Compare submitted answers with stored answers
if (hash_equals($row['answer1'], $answer1) && hash_equals($row['answer2'], $answer2)) {
$_SESSION['user_id'] = $row['user_id'];
header("Location: ResetPassword.php"); // Redirect to password reset page
exit;
} else {
$error_message = "Incorrect answers. Please try again.";
}
} else {
echo '<div class="container mt-5"><div class="alert alert-warning" role="alert">No security questions found for this user.</div></div>';
}
}
// Fetch security questions from the database for display
$sql = "SELECT question1, question2 FROM password_recovery_security_questions WHERE email = '$email'";
$result = mysqli_query($con, $sql);
if ($row = mysqli_fetch_assoc($result)) {
// Display the questions in a form
echo'<br/><br/><br/>';
echo '<div class="container">';
echo '<div class="row">';
echo '<div class="col-md-5"></div>';
echo '<div class="col-md-5">';
if (isset($error_message)) {
echo '<div id="alertbad" class="alert alert-danger" role="alert">' . $error_message . '</div>'; // Display error message
}
//echo '<center>';
echo '<form action="" method="POST" class="">';
echo '<legend>Answer Your Security Questions.</legend>';
// Question 1
echo '<div class="mb-3">';
echo '<label class="form-label">' . htmlspecialchars($row['question1']) . '</label>';
echo '<input type="text" class="form-control" name="answer1" required>';
echo '</div>';
echo'<br/>';
// Question 2
echo '<div class="mb-3">';
echo '<label class="form-label">' . htmlspecialchars($row['question2']) . '</label>';
echo '<input type="text" class="form-control" name="answer2" required>';
echo '</div>';
echo '<button id="sub" type="submit" class="btn btn-primary">Submit Answers</button>';
echo '</form>';
echo '</div></div></div>'; // Close container
} else {
echo '<div class="container mt-5"><div class="alert alert-warning" role="alert">No security questions found for this user.</div></div>';
}
} else {
header("Location: RecoverPassword.php"); // Redirect if session data is missing
exit;
}
mysqli_close($con);
?>

View File

@ -86,22 +86,22 @@ include 'Header.php';
<ul class="nav nav-tabs" id="myTab">
<li class="nav-item">
<a class="nav-link active" href="#menu1">New</a>
<a class="nav-link <?php if (!isset($_GET['tab']) || $_GET['tab'] == 'New') echo 'active'; ?>" data-toggle="tab" href="#menu1">New</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#menu2">Missed</a>
<a class="nav-link <?php if ($_GET['tab'] == 'Missed') echo 'active'; ?>" data-toggle="tab" href="#menu2">Missed</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#menu3">Submitted</a>
<a class="nav-link <?php if ($_GET['tab'] == 'Submitted') echo 'active'; ?>" data-toggle="tab" href="#menu3">Submitted</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#menu4">Marked</a>
<a class="nav-link <?php if ($_GET['tab'] == 'Marked') echo 'active'; ?>" data-toggle="tab" href="#menu4">Marked</a>
</li>
</ul>
<div class="tab-content">
<div id="menu1" class="tab-pane active">
<div id="menu1" class="tab-pane <?php if (!isset($_GET['tab']) || $_GET['tab'] == 'New') echo 'active'; ?>">
<?php
@ -152,7 +152,7 @@ include 'Header.php';
$att3 = $row['Attachment_link_3'];
$att4 = $row['Attachment_link_4'];
$labid = $row['Lab_Report_ID'];
$days_remaining = date_diff(date_create($deadline), date_create())->format('%a days, %h hours, %i minutes');
$days_remaining = "Days remaining: ".date_diff(date_create($deadline), date_create())->format('%a days, %h hours, %i minutes');
$full_link = "<a href='~\..\Download.php?file=$att1'>$att1</a>";
if($att2 != "") {
@ -165,6 +165,11 @@ include 'Header.php';
$full_link = $full_link."| <a href='~\..\Download.php?file=$att4'>$att4</a>";
}
// check if the student has already submitted the assignment
$query_result = mysqli_query($con, "SELECT * FROM lab_report_submissions WHERE Student_id=$student_id AND Lab_Report_ID=$labid");
if (mysqli_num_rows($query_result) > 0)
$days_remaining = 'You have already submitted this assignment.';
echo "<div class='card mt-md-2' style='word-wrap: break-word;'>
<div class='card-body'>
<h5 class='card-title'>$title</h5>
@ -172,7 +177,7 @@ include 'Header.php';
<p class='card-text'> $ins </p>
<p> <small>Attachments</small>: $full_link </p>
<p class='card-text'> <small> Posted: $posted &nbsp;&nbsp; Deadline: $deadline </small> </p>
<div class='alert alert-warning'>Time left: $days_remaining</div>
<div class='alert alert-warning'>$days_remaining</div>
<p><a href='~\..\SubmitLab.php?id=$labid&url=$url' class='btn btn-primary'>Submit</a></p>
</div>
</div>";
@ -185,7 +190,7 @@ include 'Header.php';
<div id="menu2" class="tab-pane">
<div id="menu2" class="tab-pane <?php if ($_GET['tab'] == 'Missed') echo 'active'; ?>">
<?php
$group_id = $_SESSION['group_id'];
@ -251,7 +256,7 @@ include 'Header.php';
<div id="menu3" class="tab-pane">
<div id="menu3" class="tab-pane <?php if ($_GET['tab'] == 'Submitted') echo 'active'; ?>">
<?php
$group_id = $_SESSION['group_id'];
@ -324,10 +329,10 @@ include 'Header.php';
$att2 = $row['Attachment2'];
$att3 = $row['Attachment3'];
$att4 = $row['Attachment4'];
$base_att1 = basename($att1);
$base_att2 = basename($att2);
$base_att3 = basename($att3);
$base_att4 = basename($att4);
$base_att1 = basename(rawurldecode($att1));
$base_att2 = basename(rawurldecode($att2));
$base_att3 = basename(rawurldecode($att3));
$base_att4 = basename(rawurldecode($att4));
$full_link = "<a href='~\..\Download.php?file=$att1&attachment=1'>$base_att1</a>"; // prevent students from directly accessing their classmates' submissions
@ -371,7 +376,7 @@ include 'Header.php';
?>
<div id="menu4" class="tab-pane">
<div id="menu4" class="tab-pane <?php if ($_GET['tab'] == 'Marked') echo 'active'; ?>">
<?php
$resultx = mysqli_query($con, "SELECT Submission_ID, Submission_Date, lab_reports_table.Lab_Report_ID, Student_id, Course_Group_id, Notes, lab_report_submissions.Marks, lab_report_submissions.Remarking_Reason, Status, lab_reports_table.Title Lab_Title, lab_reports_table.Marks Original_marks
FROM lab_report_submissions
@ -647,11 +652,12 @@ include 'Header.php';
function remarking(data)
function remarking(url)
{
const details = prompt("Please enter your remarking reasons","");
window.location.href = data+"&details="+details;
if (details != null) {
window.location.href = url+"&details="+details;
}
}

View File

@ -324,7 +324,7 @@ include 'Header.php';
}
echo "</div>";
$resultx1 = mysqli_query($con, "SELECT course_students_table.Student_ID, users_table.Full_Name
$resultx1 = mysqli_query($con, "SELECT DISTINCT course_students_table.Student_ID, users_table.Full_Name
FROM course_students_table
INNER JOIN users_table on users_table.Student_ID=course_students_table.Student_ID
WHERE Course_ID=$course_id");
@ -494,6 +494,10 @@ include 'Header.php';
echo '<hr><span class="alert alert-success" role="alert">' . $_SESSION['info_Courses_student'] . '</span>';
$_SESSION['info_Courses_student'] = null;
}
if (isset($_SESSION['info_signup'])) {
echo '<hr><div class="alert alert-danger" role="alert">' . $_SESSION['info_signup'] . '</div>';
$_SESSION['info_signup'] = null;
}
?>
<br><br>
</div>
@ -534,7 +538,7 @@ include 'Header.php';
}
if (mysqli_num_rows($result) == 0) {
echo "No results. <hr>";
echo "No such course offered in this academic year. Please check that your have entered the correct course code.<hr>";
} else {
while($row = mysqli_fetch_assoc($result)) {
$name = $row['Course_Name'];

View File

@ -1,14 +1,24 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
session_start();
error_reporting(0);
date_default_timezone_set('Asia/Shanghai');
include "get_mysql_credentials.php";
try {
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
} catch (mysqli_sql_exception $e) {
echo $e->getMessage();
}
// Check database connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
echo " Error number: ".mysqli_connect_errno();
exit();
}
?>
@ -152,7 +162,7 @@ if (mysqli_connect_errno()) {
<?php
if (isset($_SESSION["user_fullname"])) {
if ($_SESSION['user_type'] == "Student" || $_SESSION['user_type'] == 'Lecturer') {
if ($_SESSION['user_type'] == "Student" || $_SESSION['user_type'] == 'Lecturer' || $_SESSION['user_type'] == 'TA') {
echo "<a class='nav-link' href='~\..\Courses.php'><i class='fa fa-book'></i> My courses </a>";
}
?>

View File

@ -3,9 +3,9 @@
LRR (Lab Report Repository) is an online software application for course instructors to post, receive and mark assignments, and for students to submit assignments, or submit re-marking requests.
This software was originally developed by Mahomed Nor in 2018, a graduate student in the Department of Computer Science at the Zhejiang Normal University,
while he was taking a graduate course called **Advanced Software Engineering** (http://lanlab.org/course/2018f/se/homepage.html).
while he was taking a graduate course called Advanced Software Engineering.
The LRR's project home page is at http://121.4.94.30/homepage/. For potential project contributors, we recommend that you browse its home page first to familiarize yourself with the project.
For potential project contributors, we recommend that you browse its home page at ./homepage/index.html first to familiarize yourself with the project.
@ -159,7 +159,16 @@ https://github.com/spm2020spring/TeamCollaborationTutorial/blob/master/team.rst
## Testing
Make sure your changes can pass all the tests in folder [./test](http://121.4.94.30:3000/mrlan/LRR/src/branch/master/test).
Make sure your changes can pass all the tests in folder ./test.
You cannot do too much unit testing for LRR because it almost does not
have functions or classes. However, you can do end-to-end testing.
It is important that you *restore* the database each time before your
run a test case. The fixture *restore_database* in ./test/conftest.py
is used to restore the database. Please check that. A use case for
this fixture can be found in the test script
./test/SeleniumMpiana/test_bug418_yaaqob.py. You could run this test script
by typing the following command: `pytest ./SeleniumMpiana/test_bug418_yaaqob.py`
## Communications Method
@ -249,6 +258,6 @@ Nicole-Rutagengwa - Nicole Rutagengwa - 2019169
# References
- 詹沈晨. (2020). [网页程序测试自动化 (Selenium) 测试效率](http://lanlab.org/ZhanShenchen-On-Automated-Web-Application-Test-Efficiency-with-Selenium.doc)
- 詹沈晨. (2020). 网页程序测试自动化 (Selenium) 测试效率.
- Ibrahim. (2021). [Defect analysis for LRR](http://lanlab.org/thesis/Defect-Analysis-for-LRR.docx)
- Ibrahim. (2021). Defect analysis for LRR]

View File

@ -15,11 +15,9 @@ include 'Header.php';
<form method="post" action="Script.php">
<legend>Recover password</legend>
<input type="hidden" name="form_recover_password" value="true"/>
Student number
<input type="text" name="sno" placeholder="Enter your student number" class="form-control" required="required" value="<?php echo htmlspecialchars($_SESSION['student_number']); ?>"> <br/>
Email
<input type="text" name="email" placeholder="Enter your email address" class="form-control" required="required" value="<?php echo htmlspecialchars($_SESSION['user_email']); ?>"> <br/>
<button type="submit" class="btn btn-primary">Recover</button>
<button id="rec" type="submit" class="btn btn-primary">Recover</button>
</form>
</div>
</div>

78
ResetPassword.php Normal file
View File

@ -0,0 +1,78 @@
<?php
require_once 'Header.php';
require_once 'NoDirectPhpAcess.php';
require_once "get_mysql_credentials.php";
ini_set('display_errors', 0);
error_reporting(E_ALL);
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
if (mysqli_connect_errno()) {
error_log("Database connection failed: " . mysqli_connect_error());
die("An error occurred. Please try again later.");
}
// Check if user_id is set in the session
if (!isset($_SESSION['email'])) {
die("Session expired. Please log in again.");
}
$email = $_SESSION['email'];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Handle password reset
if (isset($_POST['new_password']) && isset($_POST['confirm_password'])) {
$new_password = $_POST['new_password'];
$confirm_password = $_POST['confirm_password'];
if (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\d\s]).{8,}$/', $new_password)) {
echo '<div class="alert alert-danger">Password must be at least 8 characters long and include uppercase and lowercase letters, numbers, and special characters.</div>';
} elseif ($new_password !== $confirm_password) {
echo '<div class="alert alert-danger">Passwords do not match. Please try again.</div>';
} else {
$hashed_password = password_hash($new_password, PASSWORD_ARGON2ID);
$user_id = $_SESSION['user_id'];
$stmt = $con->prepare("UPDATE users_table SET Password = ? WHERE email = ? AND user_id = ?");
$stmt->bind_param("sss", $hashed_password, $email, $user_id);
if ($stmt->execute()) {
echo '<div class="alert alert-success">Password reset successfully. You can now log in with your new password.</div>';
unset($_SESSION['user_id']); // Clear user_id after successful password reset
header("Location: index.php");
} else {
error_log("Error updating password for user ID: $user_id");
echo '<div class="alert alert-danger">An error occurred. Please try again later.</div>';
}
$stmt->close();
}
}
}
// Display the reset password form
echo '
<br/><br/><br/>
<div class="container">
<div class="row">
<div class="col-md-5"></div>
<div class="col-md-5">
<form action="" method="POST" class="">
<legend>Reset Your Password</legend><br/>
New Password <label class="form-text">Must include uppercase and lowercase letters, digits and special characters.</label>
<input type="password" name="new_password" placeholder=" Enter New Password" class="form-control" required>
<br/>
Confirm New Password
<input type="password" name="confirm_password" placeholder="Confirm New Password" class="form-control" required>
<br/>
<button id="butt" type="submit" class="btn btn-primary">Reset Password</button>
</form>
</div></div></div>
<style>
.guideline { display: none;}
#newPassword:focus + .guideline {display: block;}
';
mysqli_close($con);
?>

View File

@ -70,15 +70,20 @@ if (!empty($_POST["form_signup"])) {
// check if email is taken
$result = mysqli_query($con, "SELECT * FROM users_table WHERE email='$email'");
if (mysqli_num_rows($result) != 0) {
$_SESSION["info_signup"] = "Email address " . $email . " is already in use.";
$_SESSION['user_fullname'] = null;
header("Location: signup.php");
return;
$_SESSION["info_signup"] = "Email address " . $email . " is already in use. You have already signed up?";
}
$_SESSION['user_fullname'] = $_POST["fullname"];
$_SESSION['user_fullname_temp'] = $_POST["fullname"];
$_SESSION['user_email'] = $_POST["email"];
$_SESSION['user_student_id_temp'] = $_POST["user_student_id"];
// validate student number
if (!is_valid_student_number($student_id)) {
$_SESSION["info_signup"] = "Invalid student number.";
$_SESSION['user_fullname'] = null;
header("Location: signup.php");
return;
}
@ -87,6 +92,10 @@ if (!empty($_POST["form_signup"])) {
$result = mysqli_query($con, "SELECT * FROM `students_data` WHERE Student_ID='$student_id'");
if (mysqli_num_rows($result) == 0) {
$_SESSION["info_signup"] = "Your entered student number could not be verified. Please contact Student Management Office <lanhui at zjnu.edu.cn>. Thanks.";
$_SESSION['user_fullname'] = null;
header("Location: signup.php");
return;
}
@ -97,6 +106,7 @@ if (!empty($_POST["form_signup"])) {
$student_result = mysqli_query($con, "SELECT * FROM `users_table` WHERE Student_ID='$student_id'");
if (mysqli_num_rows($student_result) > 0) {
$_SESSION["info_signup"] = "This Student ID is already in use! Please contact Student Management Office <lanhui at zjnu.edu.cn> for help.";
$_SESSION['user_fullname'] = null;
header("Location: signup.php");
return;
}
@ -106,18 +116,75 @@ if (!empty($_POST["form_signup"])) {
if (!empty($_POST["form_signup"])) {
$fullname = mysqli_real_escape_string($con, $_POST["fullname"]);
$student_id = mysqli_real_escape_string($con, $_POST["user_student_id"]);
$_SESSION['user_fullname'] = $fullname;
$email = mysqli_real_escape_string($con, $_POST["email"]);
$password = mysqli_real_escape_string($con, $_POST["password"]);
$confirmpassword = mysqli_real_escape_string($con, $_POST["confirmpassword"]);
$_SESSION['user_student_id'] = $_POST["student_id"];
$_SESSION['user_type'] = "Student";
// check confirmed password
if (strcasecmp($password, $confirmpassword) != 0) {
$_SESSION['info_signup'] = "Password confirmation failed.";
$_SESSION['user_fullname'] = null; // such that Header.php do not show the header information.
header("Location: signup.php");
return;
}
// validate email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$_SESSION['info_signup'] = "Invalid email address.";
$_SESSION['user_fullname'] = null;
header("Location: signup.php");
return;
}
$upperLetter = preg_match('@[A-Z]@', $password);
$smallLetter = preg_match('@[a-z]@', $password);
$containsDigit = preg_match('@[0-9]@', $password);
$containsSpecial = preg_match('@[^\w]@', $password);
$containsAll = $upperLetter && $smallLetter && $containsDigit && $containsSpecial;
// check for strong password
if (!$containsAll) {
$_SESSION['info_signup'] = "Password must have at least characters that include lowercase letters, uppercase letters, numbers and special characters (e.g., !?.,*^).";
$_SESSION['user_fullname'] = null;
header("Location: signup.php");
return;
}
// check if email is taken
$result = mysqli_query($con, "SELECT * FROM users_table WHERE email='$email'");
if(mysqli_num_rows($result) != 0)
{
$_SESSION["info_signup"]="Email address ".$email." is already in use. Do you have an old LRR account?";
}
$_SESSION['user_type'] = "Student";
$_SESSION['user_email'] = $email;
$_SESSION['user_student_id'] = $student_id;
// apply password_hash()
$password_hash = password_hash($password, PASSWORD_DEFAULT);
$sql = "INSERT INTO `users_table`(`Email`, `Password`, `Full_Name`, `UserType`, `Student_ID`) VALUES "
. "('$email','$password_hash','$fullname','Student','$student_id')";
$sql = "INSERT INTO `users_table`(`Email`, `Password`, `HashPassword`, `Full_Name`, `UserType`, `Student_ID`) VALUES "
. "('$email','$password_hash','','$fullname','Student','$student_id')";
$_SESSION['user_fullname'] =$_SESSION['user_fullname_temp'];
if ($con->query($sql) === TRUE) {
header("Location: Courses.php");
// Get the newly inserted user's ID
$user_id = $con->insert_id;
//Set the user_id in the session
$_SESSION['user_id'] = $user_id;
//Redirect to SecurityQuestions.php
header("Location: SecurityQuestions.php");
} else {
echo "Something really bad (SQL insertion error) happened during sign up.";
}
@ -130,11 +197,15 @@ if (!empty($_POST["form_login"])) {
$user = mysqli_real_escape_string($con, $_POST["user"]); // user could be a 12-digit student number or an email address
$is_student_number = 0;
$_SESSION["failed_login_user"] = $user; // Save the entered username in a session variable
echo "Failed login user: " . $_SESSION["failed_login_user"];
// Validate student number
if (is_valid_student_number($user)) {
$is_student_number = 1;
}
// Validate email address if what provided is not a student number
if (!$is_student_number && !filter_var($user, FILTER_VALIDATE_EMAIL)) {
$_SESSION["info_login"] = "Invalid email address: " . "$user";
@ -160,61 +231,91 @@ if (!empty($_POST["form_login"])) {
$_SESSION['user_type'] = $row['UserType'];
$_SESSION['user_fullname'] = $row['Full_Name'];
// Check if the user is a student and has not set up their password recovery yet
if ($_SESSION['user_type'] == "Student") {
// Query to check if the student has completed the password recovery setup
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE Student_ID = '" . $row['Student_ID'] . "'");
if (mysqli_num_rows($recovery_result) == 0) {
// If the student has not set up password recovery, redirect to the setup page
header("Location: SecurityQuestions.php");
exit();
} else {
// If the student has set up password recovery, redirect to the Courses page
header("Location: Courses.php");
}
}
// Redirect other user types to their respective pages
if ($_SESSION['user_type'] == "Lecturer") {
header("Location: Courses.php");
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE user_id = '" . $row['User_ID'] . "' AND user_type = 'Lecturer'");
if (mysqli_num_rows($recovery_result) == 0) {
header("Location: SecurityQuestions.php");
exit();
} else {
header("Location: Courses.php"); }
}
if ($_SESSION['user_type'] == "TA") {
header("Location: Courses.php");
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE user_id = '" . $row['User_ID'] . "' AND user_type = 'TA'");
if (mysqli_num_rows($recovery_result) == 0) {
header("Location: SecurityQuestions.php");
exit();
} else {
header("Location: Courses.php"); }
}
if ($_SESSION['user_type'] == "Admin") {
header("Location: Admin.php");
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE user_id = '" . $row['User_ID'] . "' AND user_type = 'Admin'");
if (mysqli_num_rows($recovery_result) == 0) {
header("Location: SecurityQuestions.php");
exit();
} else {
header("Location: Admin.php"); }
}
// report wrong pass if not correct
} else {
$_SESSION["wrong_pass"] = "Wrong Password.";
header("Location: index.php");
}
}
}
}
return;
} else {
$_SESSION["wrong_pass"] = "Wrong Password.";
echo $_SESSION["wrong_pass"]; // Optional: Display the error message for debugging
header("Location: index.php");
exit(); // Add this line to prevent further execution after redirect
}
// Reset the session variable when needed
unset($_SESSION["failed_login_user"]);
}
}
}
// ################################ Recover Password #####################################
if (!empty($_POST["form_recover_password"])) {
$student_id = mysqli_real_escape_string($con, $_POST["sno"]);
$email = mysqli_real_escape_string($con, $_POST["email"]);
// validate student number
if (strlen($student_id) != 12 || is_numeric($student_id) == FALSE) {
$_SESSION["info_recover_password"] = "Invalid student number.";
header("Location: recover_password.php");
return;
}
// validate email
// Validate email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$_SESSION["info_recover_password"] = "Invalid email address.";
// echo "Invalid email address.";
header("Location: recover_password.php");
header("Location: RecoverPassword.php");
return;
}
$result = mysqli_query($con, "SELECT * FROM users_table WHERE Email='$email' and Student_ID='$student_id'");
// Check if user exists in the database
$result = mysqli_query($con, "SELECT * FROM users_table WHERE Email='$email'");
if (mysqli_num_rows($result) == 0) {
$_SESSION["info_recover_password"] = "Email address is not recognised.";
$_SESSION["info_recover_password"] = "Identity not recognized. Try again or send an inquiry email message to lanhui at zjnu.edu.cn.";
header("Location: recover_password.php");
$_SESSION["info_recover_password"] = "Email address is not recognized.";
header("Location: RecoverPassword.php");
} else {
$result = mysqli_query($con, "DELETE FROM users_table WHERE Email='$email' and Student_ID='$student_id'");
header("Location: signup.php");
// Store the student ID and email in the session
$_SESSION['email'] = $email;
header("Location: AnswerSecurityQuestions.php");
}
}
// ################################ RESET Password #####################################
@ -263,7 +364,7 @@ if (!empty($_POST["form_reset_password"])) {
}
// ############################### CREATE Lecturer/TA USER ##################################
if (!empty($_POST["form_createlecturrer"])){
if (!empty($_POST["form_createlecturer"])){
$email = mysqli_real_escape_string($con, $_POST["email"]);
$fullname = mysqli_real_escape_string($con, $_POST["fullname"]);
$type = mysqli_real_escape_string($con, $_POST["type"]);
@ -283,17 +384,15 @@ if (!empty($_POST["form_createlecturrer"])){
exit;
}
$password_hash = password_hash("$password", PASSWORD_DEFAULT);
$sql = "INSERT INTO `users_table`(`Email`, `Password`, `Full_Name`, `UserType`) VALUES "
. "('$email','$password_hash','$fullname','$type')";
$sql = "INSERT INTO `users_table`(`Email`, `Password`, `HashPassword`, `Full_Name`, `UserType`) VALUES ('$email','$password_hash','','$fullname','$type')";
if ($con->query($sql) === TRUE) {
try {
$result = mysqli_query($con, $sql);
$_SESSION["info_Admin_Users"] = $type . " user created successfully. Use email " . $email . " as account name and ". $password ." as password.";
header("Location: Admin.php");
} else {
alert("Error: " . $sql . "<br>" . $con->error);
header("Location: Admin.php?tacreated");
} catch (Exception $ex) {
echo "$ex";
}
}
// ### FUNCTION TO GENERATE INITIAL PASSWORDS ###//
@ -713,8 +812,8 @@ if (!empty($_GET["remarking"])) {
if ($con->query($sql) === TRUE) {
$_SESSION["info_general"] = "Remarking request sent";
header("Location: Course.php?url=" . $url);
$_SESSION["info_general"] = "Remarking Request Sent";
header("Location: Course.php?url=" . $url . "&tab=Marked");
} else {
echo "Error: " . $sql . "<br>" . $con->error;
}

139
SecurityQuestions.php Normal file
View File

@ -0,0 +1,139 @@
<?php
session_start();
error_reporting(0);
date_default_timezone_set('Asia/Shanghai');
include 'NoDirectPhpAcess.php';
include "get_mysql_credentials.php"; // Database credentials
error_reporting(E_ALL);
ini_set('display_errors', 1);
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
if (mysqli_connect_errno()) {
die("Connection failed: " . mysqli_connect_error());
}
// Check if user_id is set in the session
if (!isset($_SESSION['user_id'])) {
echo '<div class="alert alert-danger" role="alert">Session expired. Please log in again.</div>';
exit(); // Stop script execution if user_id is not set
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Get the security questions and answers from the form
$question1 = mysqli_real_escape_string($con, $_POST['security_question1']);
$answer1 = strtolower(mysqli_real_escape_string($con, $_POST['security_answer1']));
$question2 = mysqli_real_escape_string($con, $_POST['security_question2']);
$answer2 = strtolower(mysqli_real_escape_string($con, $_POST['security_answer2']));
// Get the user ID and user type from the session
$user_id = $_SESSION['user_id']; // Use user_id from session
$user_type = $_SESSION['user_type']; //Get user type from session
$email = $_SESSION['user_email'];
$student_id = isset($_SESSION['user_student_id']) ? $_SESSION['user_student_id'] : NULL; //Handle student_id for students
// Prepare SQL statement
if($user_type == 'Student') {
$sql = "INSERT INTO password_recovery_security_questions (user_id,user_type, student_id, email, question1, answer1, question2, answer2)
VALUES ('$user_id', '$user_type', '$student_id', '$email', '$question1', '$answer1', '$question2', '$answer2')
ON DUPLICATE KEY UPDATE
question1='$question1',
answer1='$answer1',
question2='$question2',
answer2='$answer2'";
} else {
// For non-students (Lecturer, TA, etc.), exclude student_id
$sql = "INSERT INTO password_recovery_security_questions (user_id, user_type, email, question1, answer1, question2, answer2)
VALUES ('$user_id', '$user_type', '$email', '$question1', '$answer1', '$question2', '$answer2')
ON DUPLICATE KEY UPDATE
question1='$question1',
answer1='$answer1',
question2='$question2',
answer2='$answer2'";
}
// Execute the query and check for success
if (mysqli_query($con, $sql)) {
echo '<div id="alertgood" class="alert alert-success" role="alert">Password recovery details set successfully. Please remember your answers! Redirecting to Courses page...</div>';
echo '<script>';
echo ' setTimeout(function() {';
echo ' var userType = "'. $_SESSION['user_type'] . '";';
echo ' if (userType === "Admin") {';
echo ' window.location.href = "Admin.php";';
echo ' } else {';
echo ' window.location.href = "Courses.php";';
echo ' }';
echo ' }, 2000);';
echo '</script>';
} else {
echo '<div class="alert alert-danger" role="alert">Error: ' . mysqli_error($con) . '</div>';
}
}
mysqli_close($con);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security Questions</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" style="padding-left:180px;padding-right:150px;margin:auto;">
<div class="container-fluid">
<a class="navbar-brand" href="#"> <img src="logo.png" style="width:30px;height:30px;" alt="LRR Logo"> LRR </a>
</nav>
<br/><br/><br/>
<div class="container">
<div class="col-md-5"></div>
<form action="SecurityQuestions.php" method="POST">
<label> Set Password Recovery (Make sure you remember your answers) </label>
<div class="mb-3">
<br/>
<label for="security_question1" class="form-label">Select Security Question 1</label>
<select class="form-select" id="security_question1" name="security_question1" required>
<option value="">-- Select a question --</option>
<option value="What is the name of your first pet?">What is the name of your first pet?</option>
<option value="What is your mother's maiden name?">What is your mother's maiden name?</option>
<option value="What is the name of the town where you were born?">What is the name of the town where you were born?</option>
<option value="What was the name of your first best friend?">What was the name of your first best friend?</option>
<option value="What is your favorite book?">What is your favorite book?</option>
<option value="What was the make and model of your first car?">What was the make and model of your first car?</option>
<!-- Add more options if needed -->
</select>
</div>
<div class="mb-3">
<label for="security_answer1" class="form-label">Answer 1</label>
<input type="text" class="form-control" id="security_answer1" name="security_answer1" required>
</div>
<br/>
<div class="mb-3">
<label for="security_question2" class="form-label">Select Security Question 2</label>
<select class="form-select" id="security_question2" name="security_question2" required>
<option value="">-- Select a question --</option>
<option value="What was the name of your first school?">What was the name of your first school?</option>
<option value="What is your favorite movie?">What is your favorite movie?</option>
<option value="What was your childhood nickname?">What was your childhood nickname?</option>
<option value="What is the name of your favorite teacher?">What is the name of your favorite teacher?</option>
<option value="What street did you grow up on?">What street did you grow up on?</option>
<option value="What is your favorite food?">What is your favorite food?</option>
<!-- Add more options if needed -->
</select>
</div>
<div class="mb-3">
<label for="security_answer2" class="form-label">Answer 2</label>
<input type="text" class="form-control" id="security_answer2" name="security_answer2" required>
</div>
<br/>
<button id="submit_recovery" type="submit" class="btn btn-primary">Save Answers</button>
</form>
</div>
</body>
</html>

View File

@ -151,10 +151,10 @@ echo "<div><a href='Courses.php?course=$url'> $header </a></div>";
$submitted_by = "$student_name ($submitter_student_number) for group $groupname ";
}
$base_att1 = basename($att1);
$base_att2 = basename($att2);
$base_att3 = basename($att3);
$base_att4 = basename($att4);
$base_att1 = basename(rawurldecode($att1));
$base_att2 = basename(rawurldecode($att2));
$base_att3 = basename(rawurldecode($att3));
$base_att4 = basename(rawurldecode($att4));
$full_link = "<a href='~\..\Download.php?file=$att1&attachment=1'>$base_att1</a>"; // prevent students from directly accessing their classmates' submissions

View File

@ -0,0 +1,94 @@
Contributed by Aya Boussouf 2025-05-19
# ---------------------- System Update & LAMP Stack Installation ----------------------
sudo apt update && sudo apt upgrade -y
sudo apt install apache2 mysql-server php libapache2-mod-php php-mysql unzip git -y
# ---------------------- Start and Enable Apache & MySQL Services ----------------------
sudo systemctl start apache2
sudo systemctl enable apache2
sudo systemctl start mysql
sudo systemctl enable mysql
# ---------------------- Configure MySQL Root User ----------------------
sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';
FLUSH PRIVILEGES;
exit;
# ---------------------- Create LRR Database ----------------------
mysql -u root -p
CREATE DATABASE lrr;
exit;
# ---------------------- Clone LRR Project Repository ----------------------
cd /var/www/html/
sudo git clone http://118.25.96.118:3000/mrlan/LRR.git
sudo chown -R $USER:$USER /var/www/html/LRR
# ---------------------- Switch to Hui-Organize Branch ----------------------
cd /var/www/html/LRR
git branch
git checkout -b Hui-Organize
git pull origin Hui-Organize
# ---------------------- Import SQL Data into MySQL ----------------------
sudo mysql -u root -p lrr < /var/www/html/LRR/lrr_database.sql
# ---------------------- Create Submission Folder for Assignments ----------------------
cd /var/www/
sudo mkdir lrr_submission
sudo chown -R www-data:www-data lrr_submission
sudo chmod -R g+rw lrr_submission
# ---------------------- Configure Database Credentials in KeepItSafe.txt ----------------------
sudo nano /var/www/lrr_submission/KeepItSafe.txt
# Add: root,root (username,password for MySQL connection)
# ---------------------- Configure Apache Virtual Host for LRR ----------------------
sudo nano /etc/apache2/sites-available/LRR.conf
<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
# ---------------------- Enable Apache Config and Rewrite Module ----------------------
sudo a2ensite LRR
sudo a2enmod rewrite
sudo systemctl reload apache2
# ---------------------- Install Google Chrome (for Selenium Tests) ----------------------
cd ~/Downloads
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb
# ---------------------- Install ChromeDriver ----------------------
wget https://storage.googleapis.com/chrome-for-testing-public/136.0.7103.92/linux64/chromedriver-linux64.zip
unzip chromedriver-linux64.zip
sudo mv chromedriver-linux64/chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
# ---------------------- Install Python, pip and Virtual Environment ----------------------
sudo apt install python3 python3-pip -y
sudo apt install python3-venv -y
# ---------------------- Create and Activate Virtual Environment for LRR ----------------------
cd /var/www/html/LRR
python3 -m venv venv
source venv/bin/activate
# ---------------------- Install Required Python Packages ----------------------
pip install selenium
pip install pytest
# ---------------------- Run Selenium Tests ----------------------
cd test
# Make necessary edits in `conftest.py` and `test_lrr.py`.
pytest -v SeleniumHui/test_lrr.py

View File

@ -30,7 +30,7 @@ if (isset($_SESSION["user_fullname"])) {
<legend>Sign in</legend>
<input type="hidden" name="form_login" value="true"/>
<label for="user_name" class="form-label">Account name</label>
<input type="text" name="user" placeholder="Student Number / Email address" class="form-control" required="required" id="user_name" />
<input type="text" name="user" placeholder="Student Number / Email address" class="form-control" required="required" id="user_name" value="<?php echo isset($_SESSION['failed_login_user']) ? htmlspecialchars($_SESSION['failed_login_user']) : ''; ?>" />
<br>
<label for="user_password" class="form-label">Password</label>
<input type="password" class="form-control" name="password" placeholder="password" required="required" id="user_password" />
@ -41,7 +41,7 @@ if (isset($_SESSION["user_fullname"])) {
<label class="form-text">Don't have an account yet?</label> <a href="signup.php" id="signup_link">Sign up</a>
<br>
<label class="form-text">Forget your password?</label> <a href="recover_password.php">Recover</a>
<label class="form-text">Forget your password?</label> <a id="goRecover" href="RecoverPassword.php">Recover</a>
<?php

View File

@ -61,7 +61,7 @@ CREATE TABLE `courses_table` (
INSERT INTO `courses_table` (`Course_ID`, `Course_Name`, `Academic_Year`, `Faculty`, `Lecturer_User_ID`, `TA_User_ID`, `Course_Code`, `URL`, `Verify_New_Members`) VALUES
(10, 'Software Engineering', '2018', 'Computing', 8, 0, 'CSC1234', 'CSC12342018', '1'),
(11, 'Project Management', '2019', 'Computing', 8, 0, 'P.M2019', 'P.M20192019', '0'),
(11, 'Project Management', '2024', 'Computing', 8, 0, 'CSC1111', 'CSC11112024', '0'),
(12, 'Ashly Course Testing', '2020', 'Testing', 8, 0, 'Teecloudy', 'Teecloudy2020', '1');
-- --------------------------------------------------------
@ -136,7 +136,7 @@ INSERT INTO `course_students_table` (`Course_ID`, `Student_ID`, `ID`, `Status`)
(10, '201825800050', 13, 'Joined'),
(10, '201825800054', 14, 'Joined'),
(12, '201632120150', 15, 'Joined'),
(12, '2016321201502', 16, 'Joined'),
(12, '201632120150', 16, 'Joined'),
(12, '201825800050', 17, 'Joined');
-- --------------------------------------------------------
@ -200,7 +200,7 @@ CREATE TABLE `lab_reports_table` (
INSERT INTO `lab_reports_table` (`Lab_Report_ID`, `Course_ID`, `Posted_Date`, `Deadline`, `Instructions`, `Title`, `Attachment_link_1`, `Attachment_link_2`, `Attachment_link_3`, `Attachment_link_4`, `Marks`, `Type`) VALUES
(1, 10, '2019-01-11 16:52', '2019-02-11 17:00', 'Description of the lab....', 'Reading 1', '700IMPORTANT WORDS.txt', '', '', '', '4', 'Individual'),
(2, 10, '2019-01-17 11:12', '2019-01-25 23:59', 'Read this paper http://sunnyday.mit.edu/16.355/budgen-david.pdf', 'Reading 2', '586LRR-Test-caseS.pdf', '', '', '', '6', 'Individual'),
(2, 10, '2024-09-29 11:12', '2025-07-30 23:59', 'Read this paper http://sunnyday.mit.edu/16.355/budgen-david.pdf', 'Reading 2', '586LRR-Test-caseS.pdf', '', '', '', '6', 'Individual'),
(3, 12, '2020-04-05 02:48', '2020-04-12 ', 'Do this assignment in time for testing', 'First Assignment Testing', '', '', '', '', '3', 'Group'),
(4, 12, '2020-04-05 05:36', '2020-04-06 ', 'We are testing to see if the instructor can be able to modify the work', 'Second Assignment Testing', '', '', '', '', '3', 'Individual'),
(5, 12, '2020-04-05 05:51', '2020-04-08 ', 'ASQDASDASCDD', 'Third Assignment Testingas', '', '', '', '', '3', 'Individual'),
@ -235,7 +235,7 @@ CREATE TABLE `lab_report_submissions` (
--
INSERT INTO `lab_report_submissions` (`Submission_ID`, `Submission_Date`, `Lab_Report_ID`, `Student_id`, `Course_Group_id`, `Attachment1`, `Notes`, `Attachment2`, `Attachment3`, `Attachment4`, `Marks`, `Status`, `Title`, `Visibility`, `Remarking_Reason`) VALUES
(1, '2019-01-17 00:00:00', 1, '201825800050', 0, 'Reading list.txt', '-', '', '', '', 5, 'Marked', 'Reading 1 submission', 'Public', ''),
(1, '2019-01-17 00:00:00', 1, '201825800050', 0, 'Reading list.txt', '-', '', '', '', NULL, 'Pending', 'Reading 1 submission', 'Public', ''),
(5, '2019-01-21 08:31:00', 2, '201825800050', 0, 'Trial Balance.txt', ' - @2019-01-21 09:35 : Sorry I missed some details from your report', 'Boorka.jpg', '', '', 6, 'Marked', 'Submission x', 'Private', ''),
(30, '2020-04-06 23:18:00', 3, '0', 31, '/2016321201502/First Assignment Testing/UR Diagram.pdf', '<br>@2020-04-06 23:19 : ', '', '', '', 3, 'Marked', 'First Assignment Testing', 'Private', '');
@ -259,7 +259,11 @@ INSERT INTO `students_data` (`ID`, `Student_ID`, `Passport_Number`) VALUES
(1, '201825800054', 'LJ7951632'),
(2, '201825800050', 'P00581929'),
(3, '201632120150', 'FN524516'),
(4, '11', '11');
(4, '202400000001', 'NA'),
(5,'201932130101',''),
(6,'201920781742','');
-- --------------------------------------------------------
@ -268,7 +272,7 @@ INSERT INTO `students_data` (`ID`, `Student_ID`, `Passport_Number`) VALUES
--
CREATE TABLE `users_table` (
`User_ID` int(11) NOT NULL,
`User_ID` int(11) NOT NULL AUTO_INCREMENT,
`Email` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
`Password` varchar(250) CHARACTER SET utf8 DEFAULT NULL,
`HashPassword` varchar(250) COLLATE utf8mb4_bin NOT NULL,
@ -276,7 +280,8 @@ CREATE TABLE `users_table` (
`UserType` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
`Student_ID` varchar(500) COLLATE utf8mb4_bin DEFAULT NULL,
`Passport_Number` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
`Status` varchar(30) COLLATE utf8mb4_bin NOT NULL DEFAULT 'Active'
`Status` varchar(30) COLLATE utf8mb4_bin NOT NULL DEFAULT 'Active',
PRIMARY KEY (`User_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
--
@ -285,15 +290,36 @@ CREATE TABLE `users_table` (
INSERT INTO `users_table` (`User_ID`, `Email`, `Password`, `HashPassword`, `Full_Name`, `UserType`, `Student_ID`, `Passport_Number`, `Status`) VALUES
(3, 'admin@qq.com', '$2y$10$8GCG6lTo1LFRD3bOkAyKYeOMOrFSBUgrTxaPLS5ynWN1bYDHf89pO', '', 'Kamal', 'Admin', '0', NULL, 'Active'),
(8, 'lanhui@qq.com', '1234', '', 'Lanhui', 'Lecturer', NULL, '123', 'Active'),
(9, 'mohamed@qq.com', '123', '', 'Mohamed', 'Student', '201825800050', 'P00581929', 'Active'),
(7, 'peter@qq.com', '$2y$10$8GCG6lTo1LFRD3bOkAyKYeOMOrFSBUgrTxaPLS5ynWN1bYDHf89pO', '', 'Peter', 'Lecturer', NULL, '123', 'Active'),
(8, 'lanhui@qq.com', '$2y$10$8GCG6lTo1LFRD3bOkAyKYeOMOrFSBUgrTxaPLS5ynWN1bYDHf89pO', '', 'Lanhui', 'Lecturer', NULL, '123', 'Active'),
(9, 'mohamed@qq.com', '$2y$10$8GCG6lTo1LFRD3bOkAyKYeOMOrFSBUgrTxaPLS5ynWN1bYDHf89pO', '', 'Mohamed', 'Student', '201825800050', 'P00581929', 'Active'),
(10, 'mark@qq.com', '123', '', 'Mark ', 'TA', NULL, '123', 'Active'),
(11, 'john@qq.com', '123', '', 'John', 'TA', NULL, '123', 'Active'),
(12, 'mehdi@qq.com', '123', '', 'El-mehdi Houzi', 'Student', '201825800054', 'LJ7951632', 'Active'),
(17, 'teecloudy@qq.com', '$2y$10$8WqSK7QI.3YCb2yoclqutOxyGxojncUvzhqLcE8zjlSvjBdcIQ18O', '', 'Ashly Tafadzwa Dhani', 'Student', '201632120150', NULL, 'Active'),
(18, 'ashly@qq.com', 'Testing2', '', 'Ashly 2 Testing', 'Student', '2016321201502', NULL, 'Active'),
(19, '11@11.11', 'dfdf', '760a8f4f392f1f6bc3ecb118365c6cd039b59fdce96122897d5157970d9c9c129bd73b3c402dbeedd8fe94d319df7bd7de0025c22839fec06631a025ec1e0e69', '11', 'Student', '11', '', 'Active');
(19, '11@11.11', 'dfdf', '760a8f4f392f1f6bc3ecb118365c6cd039b59fdce96122897d5157970d9c9c129bd73b3c402dbeedd8fe94d319df7bd7de0025c22839fec06631a025ec1e0e69', '11', 'Student', '11', '', 'Active'),
(20,'goodstd@qq.com','$2y$10$RXIjONOK.mw74pSxPrsnGuccQsFq4O4.e71vaxfGHHhtzHREtfqkG','','Good Std','Student','201932130101',NULL,'Active'),(21,'goodstd2@qq.com','$2y$10$kmqrGuZd7hCiiaHFDQr2vObpD7BgEnCKlgQ/EcLHYnsQenMbNKcHy','','Good Std2','Student','201920781742',NULL,'Active');
CREATE TABLE `password_recovery_security_questions` (
`user_id` int NOT NULL,
`user_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`student_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`question1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`answer1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`question2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`answer2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`user_id`),
CONSTRAINT `password_recovery_security_questions_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_table` (`User_ID`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
INSERT INTO `password_recovery_security_questions` VALUES
(3,'Admin',NULL,'admin@qq.com','What is the name of your first pet?','mimi','What was the name of your first school?','zjnu'),
(7,'Lecturer',NULL,'peter@qq.com','What was the name of your first best friend?','chen','What is your favorite food?','hotpot'),
(8,'Lecturer',NULL,'lanhui@qq.com','What is the name of the town where you were born?','jinhua','What is your favorite movie?','titanic'),
(9,'Student','201825800050','mohamed@qq.com','What was the make and model of your first car?','audi','What is the name of your favorite teacher?','chen'),
(21,'Student','201920781742','goodstd2@qq.com','What is the name of the town where you were born?','wenzhou','What is your favorite food?','hotpot');
--
-- Indexes for dumped tables
--
@ -347,12 +373,6 @@ ALTER TABLE `lab_report_submissions`
ALTER TABLE `students_data`
ADD PRIMARY KEY (`ID`);
--
-- Indexes for table `users_table`
--
ALTER TABLE `users_table`
ADD PRIMARY KEY (`User_ID`);
--
-- AUTO_INCREMENT for dumped tables
--
@ -410,12 +430,7 @@ ALTER TABLE `students_data`
--
ALTER TABLE courses_table
MODIFY Course_Name varchar(500);
--
-- AUTO_INCREMENT for table `users_table`
--
ALTER TABLE `users_table`
MODIFY `User_ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=20;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

View File

@ -22,10 +22,10 @@ include 'Header.php';
<input type="hidden" name="form_signup" value="true" />
Full Name
<input type="text" name="fullname" placeholder="Your full name" class="form-control" value="<?php echo $_SESSION['user_fullname']; ?>" required="required" id="full_name"/> <br>
<input type="text" name="fullname" placeholder="Your full name" class="form-control" value="<?php echo isset($_SESSION['user_fullname_temp']) ? $_SESSION['user_fullname_temp'] : ''; ?>" required="required" id="full_name"/> <br>
Student ID
<input type="text" name="user_student_id" placeholder="Entre your student ID" class="form-control" value="<?php echo $_SESSION['user_student_id']; ?>" required="required" id="student_id"> <br>
<input type="text" name="user_student_id" placeholder="Entre your student ID" class="form-control" value="<?php echo isset($_SESSION['user_student_id_1']) ? $_SESSION['user_student_id_temp'] : ''; ?>" required="required" id="student_id"> <br>
Email
<input type="text" name="email" placeholder="Email" class="form-control" value="<?php echo $_SESSION['user_email']; ?>" required="required" id="email" /> <br>

View File

@ -0,0 +1,37 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, UnexpectedAlertPresentException
def login(driver, url, username, password):
try:
driver.get(url)
# Fill in the login form
user_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "user_name"))
)
user_input.send_keys(username)
password_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "user_password"))
)
password_input.send_keys(password)
# Click the login button
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "login_btn"))
)
login_button.click()
except (NoSuchElementException, UnexpectedAlertPresentException) as e:
return f"Error: {str(e)}"
def logout(driver):
logout_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable(
(By.XPATH, "//a[contains(@class, 'nav-link') and contains(@href, 'logout.php')]")
)
)
logout_button.click()

View File

@ -0,0 +1,156 @@
from helper import login, logout
import time
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
def test_attempt_recovery_with_unanswered_security_questions(driver, url, restore_database):
# Student goodstd@qq.com with no answered questions
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
wait = WebDriverWait(driver, 10)
alert_elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "alert-warning")))
assert "no security questions found for this user." in alert_elem.text.lower()
driver.quit()
def test_set_security_questions(driver, url, restore_database):
# Student goodstd@qq.com logs in
driver.get(url)
driver.maximize_window()
login(driver, url, 'goodstd@qq.com', '[123Abc]')
question1 = driver.find_element(By.ID, 'security_question1')
question2 = driver.find_element(By.ID, 'security_question2')
select_question1 = Select(question1)
select_question1.select_by_index(1)
select_question2 = Select(question2)
select_question2.select_by_index(2)
answer1 = driver.find_element(By.ID, 'security_answer1')
answer1.send_keys("mImI")
answer2 = driver.find_element(By.ID, 'security_answer2')
answer2.send_keys("TitaNic")
submit_button = driver.find_element(By.ID, 'submit_recovery')
submit_button.click()
# Assertion: Check if password recovery confirmation or success message appears
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'alertgood')))
recovery_success = driver.find_element(By.ID, 'alertgood')
assert recovery_success.is_displayed(), "Password recovery failed or confirmation message not displayed."
logout(driver)
#Log in Student account
login(driver, url, 'goodstd@qq.com', '[123Abc]')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert 'Student ID' in elems[0].text
assert 'Good Std' in elems[0].text
driver.quit()
def test_password_recover_wrong_answers(driver, url, restore_database):
# Student goodstd2@qq.com recover password --> wrong answers
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd2@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
elem = driver.find_element(By.NAME, 'answer1')
elem.send_keys("wrong")
elem = driver.find_element(By.NAME, 'answer2')
elem.send_keys("wrong")
elem = driver.find_element(By.ID, 'sub')
elem.click()
driver.quit()
def test_recover_password_with_weak_password(driver, url, restore_database):
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd2@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
elem = driver.find_element(By.NAME, 'answer1')
elem.send_keys("Wenzhou")
elem = driver.find_element(By.NAME, 'answer2')
elem.send_keys("HotPot")
elem = driver.find_element(By.ID, 'sub')
elem.click()
elem = driver.find_element(By.NAME, 'new_password')
elem.send_keys("123")
elem = driver.find_element(By.NAME, 'confirm_password')
elem.send_keys("123")
elem = driver.find_element(By.ID, "butt")
elem.click()
wait = WebDriverWait(driver, 10)
alert_elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "alert-danger")))
assert "password must be at least 8 characters long and include uppercase and lowercase letters, numbers, and special characters." in alert_elem.text.lower()
driver.quit()
def test_recover_password_successfully(driver, url, restore_database):
# Student goodstd2@qq.com recover password ---> correct answers
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd2@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
elem = driver.find_element(By.NAME, 'answer1')
elem.send_keys("wenzhou")
elem = driver.find_element(By.NAME, 'answer2')
elem.send_keys("hotpot")
elem = driver.find_element(By.ID, 'sub')
elem.click()
elem = driver.find_element(By.NAME, 'new_password')
elem.send_keys("123Abc!!")
elem = driver.find_element(By.NAME, 'confirm_password')
elem.send_keys("123Abc!!")
elem = driver.find_element(By.ID, "butt")
elem.click()
#Log in Student account
login(driver, url, 'goodstd2@qq.com', '123Abc!!')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert 'Student ID' in elems[0].text
assert 'Good Std2' in elems[0].text
driver.quit()
def test_recovery_invalid_user_cannot_recover(driver, url, restore_database):
# Unrecognizable user cannot recover
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd3@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
wait = WebDriverWait(driver, 10)
alert_elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "alert-danger")))
assert "email address is not recognized." in alert_elem.text.lower()
driver.quit()

View File

@ -0,0 +1,46 @@
Sign-Up Automation Test Script
Overview
This script automates the sign-up process for a web application using Selenium WebDriver. It tests whether form values are retained correctly if the initial sign-up attempt fails and requires modification of the student ID before resubmission.
Prerequisites
Python 3
Selenium library
Chrome WebDriver
A running instance of the web application on http://localhost:8080
Configuration
Web Application URL: Make sure the web application is running at http://localhost:8080. Adjust the URL in the script if necessary.
Update Element Locators: Ensure the IDs used in the script (signup_link, signup_form, full_name, student_id, email, password1, password2, signup_btn) match those in your web application.
Run the script:
Script Logic
Open the Login Page: The script navigates to the login page of the web application.
Click the "Sign Up" Link: It waits for the "Sign Up" link to appear and clicks it to navigate to the sign-up page.
Fill Out the Sign-Up Form: It fills out the form fields (Full Name, Student ID, Email, Password).
Submit the Form: It submits the form and waits for the result.
Check for Sign-Up Failure: If sign-up fails, it checks if form values are retained.
Modify Student ID: If the form values are retained, it modifies the student ID and resubmits the form.
Verify Retained Values: It verifies if other fields retain their values after modifying the student ID.
Print Retained Values: If the second attempt is successful, it prints the retained form values.
Close the Browser: The browser is closed at the end of the script execution.
The script provides the following output:
Sign-Up Successful: Indicates the sign-up was successful on the first attempt.
Sign-Up Failed: Indicates the sign-up failed on the first attempt and checks for retained values.
Second Sign-Up Attempt Successful: Indicates the second sign-up attempt was successful and prints the retained values.
Second Sign-Up Attempt Failed: Indicates the second sign-up attempt also failed, suggesting further investigation is needed.
Notes
Form Field IDs: Ensure the IDs used in the script match those in your web application.
Password Fields: The script intentionally does not print password fields for security reasons.
Adjust Wait Times: Modify the wait times as needed depending on your application's response times.
Troubleshooting
Element Not Found: Verify the element IDs and update them in the script.
WebDriver Errors: Ensure the Chrome WebDriver is installed and matches your Chrome browser version.
Connection Errors: Ensure the web application is running and accessible at the specified URL.
Contributing

88
test/SeleniumEden/test.py Normal file
View File

@ -0,0 +1,88 @@
import time # Import time module for waiting
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# New instance of the Chrome driver
driver = webdriver.Chrome()
try:
# Step 1: Open the login page
driver.get("http://localhost:8080/lrr/lrr/admin.php") # Replace with your actual login page URL
# Step 2: Wait for the login page to fully load and locate the "Sign Up" link
sign_up_link = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "signup_link"))
)
# Step 3: Click the "Sign Up" link to navigate to the sign-up page
sign_up_link.click()
# Step 4: Wait for the sign-up page to fully load
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "signup_form"))
)
# Step 5: Fill out the sign-up form
driver.find_element(By.ID, "full_name").send_keys("John Doe")
driver.find_element(By.ID, "student_id").send_keys("12345678")
driver.find_element(By.ID, "email").send_keys("john.doe@example.com")
driver.find_element(By.ID, "password1").send_keys("Password123!")
driver.find_element(By.ID, "password2").send_keys("Password123!")
# Step 6: Submit the sign-up form
driver.find_element(By.ID, "signup_btn").click()
# Step 7: Wait for the sign-up result
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Check if sign-up failed
if "alert-danger" in driver.page_source:
print("Sign-up failed. Checking if form values are retained...")
# Wait for a few seconds (adjust as needed)
time.sleep(3)
# Modify the student ID again
driver.find_element(By.ID, "student_id").clear()
driver.find_element(By.ID, "student_id").send_keys("87654321")
# Verify if the other fields retain their values
assert driver.find_element(By.ID, "full_name").get_attribute("value") == "John Doe"
assert driver.find_element(By.ID, "email").get_attribute("value") == "john.doe@example.com"
assert driver.find_element(By.ID, "password1").get_attribute("value") == ""
assert driver.find_element(By.ID, "password2").get_attribute("value") == ""
# Resubmit the form
driver.find_element(By.ID, "signup_btn").click()
# Wait for the result again
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Check for success or failure after second attempt
if "alert-danger" in driver.page_source:
print("Second sign-up attempt failed. Further investigation needed.")
# Print the retained values
print("Retained form values after second attempt:")
print("Full Name:", driver.find_element(By.ID, "full_name").get_attribute("value"))
print("Email:", driver.find_element(By.ID, "email").get_attribute("value"))
# Password fields might be intentionally cleared, so they won't be printed here
print("Modified Student ID:", driver.find_element(By.ID, "student_id").get_attribute("value"))
else:
print("Second sign-up attempt successful!")
else:
print("Sign-up successful!")
finally:
# Close the browser
driver.quit()

View File

@ -0,0 +1,6 @@
Sign-up failed. Checking if form values are retained...
Second sign-up attempt failed. Further investigation needed.
Retained form values after second attempt:
Full Name: John Doe
Email: john.doe@example.com
Modified Student ID: 87654321

View File

@ -0,0 +1,37 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, UnexpectedAlertPresentException
def login(driver, url, username, password):
try:
driver.get(url)
# Fill in the login form
user_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "user_name"))
)
user_input.send_keys(username)
password_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "user_password"))
)
password_input.send_keys(password)
# Click the login button
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "login_btn"))
)
login_button.click()
except (NoSuchElementException, UnexpectedAlertPresentException) as e:
return f"Error: {str(e)}"
def logout(driver):
logout_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable(
(By.XPATH, "//a[contains(@class, 'nav-link') and contains(@href, 'logout.php')]")
)
)
logout_button.click()

View File

@ -0,0 +1,364 @@
from helper import login, logout
import time
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def test_admin_can_create_lecturer_account(driver, url, admin_username, admin_password, restore_database):
# Administrator (admin@qq.com, password 123) logs in
driver.maximize_window()
login(driver, url, admin_username, admin_password)
# Create a Lecturer account for Mr Lan (mrlan@qq.com, password [123Abc!])
tab = driver.find_element(By.ID, 'tab_ins_accounts')
tab.click()
elem = driver.find_element(By.NAME, 'fullname')
elem.send_keys('Mr Lan')
elem = driver.find_element(By.NAME, 'email')
elem.send_keys('mrlan@qq.com')
elem = driver.find_element(By.NAME, 'password')
elem.send_keys('123Abc!!')
radio_button = driver.find_element(By.NAME, 'type')
radio_button.click()
button = driver.find_element(By.NAME, 'create_btn')
button.click()
# Log out Admin account
logout(driver)
# Log in Lecturer account
login(driver, url, 'mrlan@qq.com', '123Abc!!')
#elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
#assert '(Lecturer)' in elems[0].text
#assert 'Mr Lan' in elems[0].text
wait = WebDriverWait(driver, 10)
wait.until(EC.url_contains('SecurityQuestions.php'))
driver.quit()
def test_lecturer_can_create_course(driver, url, restore_database):
# Lecturer lanhui@qq.com logs in
driver.maximize_window()
login(driver, url, 'lanhui@qq.com', '123')
# Create a course called CSC1001 Advanced Software Engineering, 2024
elem = driver.find_element(By.NAME, 'name')
elem.send_keys('Advanced Software Engineering')
elem = driver.find_element(By.NAME, 'code')
elem.send_keys('CSC1001')
elem = driver.find_element(By.NAME, 'academic')
elem.send_keys('2004')
elem = driver.find_element(By.NAME, 'faculty')
elem.send_keys('School of Computer Science and Technology')
elem = driver.find_element(By.CLASS_NAME, 'btn-primary')
elem.click()
elems = driver.find_elements(By.CLASS_NAME, 'btn-default')
last_elem = elems[-1]
assert 'Advanced Software Engineering' in last_elem.text
assert '(CSC1001)' in last_elem.text
# Logout
logout(driver)
driver.quit()
def test_lecturer_can_post_assignment(driver, url, restore_database):
# Lecturer lanhui@qq.com logs in
driver.maximize_window()
login(driver, url, 'lanhui@qq.com', '123')
# Create an assignment called Take-home quiz 1 for course (CSC1111) - Project Management
elem = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, '//div[@class="col-md-8"]/a[1]/div'))
)
elem.click()
elem = driver.find_element(By.NAME, 'deadlinedate')
elem.send_keys('002025/05/30')
elem = driver.find_element(By.NAME, 'deadlinetime')
elem.send_keys('23:59')
elem = driver.find_element(By.NAME, 'title')
elem.send_keys('Take-home quiz 1')
elem = driver.find_element(By.NAME, 'instructions')
elem.send_keys('This is a closed-book quiz.')
elem = driver.find_element(By.NAME, 'marks')
elem.send_keys('10')
radio_button = driver.find_element(By.NAME, 'type')
radio_button.click()
elem = driver.find_element(By.CLASS_NAME, 'btn-primary')
elem.click()
# Check if the assignment has been successfully posted
elem = driver.find_element(By.CLASS_NAME, 'card-title')
assert 'Take-home quiz 1 (10 Marks, Individual)' in elem.text
elem = driver.find_element(By.CLASS_NAME, 'text-muted')
assert 'Deadline: 2025-05-30' in elem.text
driver.quit()
def test_lecturer_can_add_student_numbers(driver, url, restore_database):
# Lecturer lanhui@qq.com logs in
driver.maximize_window()
login(driver, url, 'lanhui@qq.com', '123')
# Add ASE student numbers
student_numbers = '''
202420781739
202420781740
202420781741
202420781742
202420781743
202420781745
202420581366
202420581368
202420581369
202420581370
202420581372
202420581373
202420581374
202420581376
202420581378
202420581381
'''
elem = driver.find_element(By.ID, 'admin_tab')
elem.click()
elem = driver.find_element(By.NAME, 'users')
elem.send_keys(student_numbers)
elem = driver.find_element(By.ID, 'register_btn')
elem.click()
elems = driver.find_elements(By.CSS_SELECTOR, 'p')
added = 0
student_lst = [number.strip() for number in student_numbers.strip().split('\n')]
print(student_lst)
for student_no in student_lst:
for elem in elems:
if student_no in elem.text and 'added' in elem.text:
added += 1
break
assert added == len(student_lst)
driver.quit()
def test_student_with_valid_student_number_can_sign_up(driver, url, restore_database):
# Student with recognizable student number 202400000001 can sign up an account
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'signup_link')
elem.click()
elem = driver.find_element(By.NAME, 'fullname')
elem.send_keys('Good Student')
elem = driver.find_element(By.NAME, 'user_student_id')
elem.send_keys('202400000001')
elem = driver.find_element(By.NAME, 'email')
elem.send_keys('goodstudent@qq.com')
elem = driver.find_element(By.NAME, 'password')
elem.send_keys('[123Abc]')
elem = driver.find_element(By.NAME, 'confirmpassword')
elem.send_keys('[123Abc]')
elem = driver.find_element(By.ID, 'signup_btn')
elem.click()
driver.get(url + 'logout.php')
# Log in Student account
login(driver, url, '202400000001', '[123Abc]')
#elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
#assert 'Student ID' in elems[0].text
#assert 'Good Student' in elems[0].text
wait = WebDriverWait(driver, 10)
wait.until(EC.url_contains('SecurityQuestions.php'))
driver.quit()
def test_student_with_invalid_student_number_cannot_sign_up(driver, url, restore_database):
# Student with unrecognizable student number cannot sign up an account
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'signup_link')
elem.click()
elem = driver.find_element(By.NAME, 'fullname')
elem.send_keys('Good Student')
elem = driver.find_element(By.NAME, 'user_student_id')
elem.send_keys('202400000002')
elem = driver.find_element(By.NAME, 'email')
elem.send_keys('goodstudent@qq.com')
elem = driver.find_element(By.NAME, 'password')
elem.send_keys('[123Abc]')
elem = driver.find_element(By.NAME, 'confirmpassword')
elem.send_keys('[123Abc]')
elem = driver.find_element(By.ID, 'signup_btn')
elem.click()
# Log in Student account
login(driver, url, '202400000002', '[123Abc]')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert not 'Student ID' in elems[0].text
assert not 'Good Student' in elems[0].text
driver.quit()
def test_student_with_weak_password_cannot_sign_up(driver, url, restore_database):
driver.get(url)
driver.maximize_window()
weak_password = '123Abc'
elem = driver.find_element(By.ID, 'signup_link')
elem.click()
elem = driver.find_element(By.NAME, 'fullname')
elem.send_keys('Good Student')
elem = driver.find_element(By.NAME, 'user_student_id')
elem.send_keys('202400000001')
elem = driver.find_element(By.NAME, 'email')
elem.send_keys('goodstudent@qq.com')
elem = driver.find_element(By.NAME, 'password')
elem.send_keys(weak_password)
elem = driver.find_element(By.NAME, 'confirmpassword')
elem.send_keys(weak_password)
elem = driver.find_element(By.ID, 'signup_btn')
elem.click()
# Log in Student account
login(driver, url, '202400000001', weak_password)
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert not 'Student ID' in elems[0].text
assert not 'Good Student' in elems[0].text
driver.quit()
def test_student_can_join_course(driver, url, restore_database):
# Student can join (CSC1111) - Project Management
login(driver, url, '201825800050', '123')
driver.maximize_window()
# Search for CSC1111
elem = driver.find_element(By.NAME, 'search')
elem.send_keys('CSC1111')
elem = driver.find_element(By.CLASS_NAME, 'btn-primary')
elem.click()
elems = driver.find_elements(By.CLASS_NAME, 'btn-default')
assert 'CSC1111' in elems[0].text
# Join
elem = driver.find_element(By.CLASS_NAME, 'btn-success') # find the green Join button
elem.click()
# Log out, then log in to check the course-joining status
logout(driver)
login(driver, url, '201825800050', '123')
elems = driver.find_elements(By.CLASS_NAME, 'btn-default')
assert 'CSC1111' in elems[0].text
assert 'Project Management' in elems[0].text
assert 'Joined' in elems[0].text
driver.quit()
def test_student_can_submit_assignment(driver, url, restore_database):
''' Note: Make sure the fields Posted_Date and Deadline in the second row of lab_reports_table are in the current year'''
# Student can submit assignment for CSC1111
login(driver, url, '201825800050', '123')
driver.maximize_window()
# Enter into the course and the find the assignment
elems = driver.find_elements(By.CLASS_NAME, 'btn-default')
elems[1].click()
elem = driver.find_element(By.XPATH, '//div[@id="menu1"]/div/div/p/a[text()="Submit"]') # find the submit button
elem.click()
# Fill submission title, attach file, and submit
elem = driver.find_element(By.NAME, 'title')
elem.send_keys('Assignment submission from Mohamed')
elem = driver.find_element(By.NAME, 'attachment1')
elem.send_keys('/var/www/html/LRR/test/SeleniumHui/helper.py') # attach a file
elem = driver.find_element(By.XPATH, '//form/button')
elem.click()
# Go the Submitted tab
elem = driver.find_element(By.ID, 'myTab')
elems = elem.find_elements(By.CLASS_NAME, 'nav-link')
elems[2].click()
elem = driver.find_element(By.XPATH, '//div[@id="menu3"]/div')
assert 'Reading 2 (6 Marks)' in elem.text
assert 'SUBMITTED' in elem.text
assert 'helper.py' in elem.text
driver.quit()
def test_student_can_request_remarking(driver, url, restore_database):
# Student logs in
login(driver, url, '201825800050', '123')
driver.maximize_window()
# Enter into the course
elems = driver.find_elements(By.CLASS_NAME, 'btn-default')
elems[1].click()
# Go the Marked tab
elem = driver.find_element(By.ID, 'myTab')
elems = elem.find_elements(By.CLASS_NAME, 'nav-link')
elems[3].click()
# Send remarking request
remarking_buttons = driver.find_elements(By.CLASS_NAME, 'btn-light')
remarking_buttons[0].click()
alert = driver.switch_to.alert
alert.send_keys('I need higher marks, teacher.')
alert.accept()
elem = driver.find_element(By.XPATH, '//div[@id="menu4"]/div/div/p/span')
assert 'Remarking request sent' == elem.text
driver.quit()
def test_lecturer_can_mark_assignment(driver, url, restore_database):
# Lecturer lanhui@qq.com logs in
driver.maximize_window()
login(driver, url, 'lanhui@qq.com', '123')
# Enter into the course and the find the assignment
elem = driver.find_element(By.XPATH, '//div[1]/a[3]/div') # course Software Engineering
elem.click()
elem = driver.find_element(By.XPATH, '//div[2]/div[2]/div/a[2]') # View link
elem.click()
elem = driver.find_element(By.CLASS_NAME, 'btn-primary') # Blue Mark button
elem.click()
# Submit mark and comment
elem = driver.find_element(By.NAME, 'marks')
elem.send_keys('1')
elem = driver.find_element(By.NAME, 'feedback')
elem.send_keys('Inadequate')
form = driver.find_element(By.ID, 'submit-form')
form.submit()
elem = driver.find_element(By.ID, 'myTab')
elems = elem.find_elements(By.CLASS_NAME, 'nav-link')
assert 'Marked submissions (1)' == elems[1].text
elems[1].click()
elem = driver.find_element(By.XPATH, "//div[@id='menu2']/div/b")
assert 'Reading 1 submission' in elem.text
driver.quit()
def test_lecturer_cannot_see_tas_not_from_his_course(driver, url, restore_database):
# Lecturer lanhui@qq.com logs in
driver.maximize_window()
login(driver, url, 'peter@qq.com', '123')
elem = driver.find_element(By.ID, 'admin_tab')
elem.click()
tab = driver.find_element(By.ID, 'existing_accounts_tab')
tab.click()
elem = driver.find_element(By.ID, 'tab-existing-accounts')
assert 'No TA' in elem.text
# Logout
logout(driver)
driver.quit()

View File

@ -0,0 +1,77 @@
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, TimeoutException
import time
import traceback
driver = webdriver.Chrome()
try:
# Navigate to the page with tabs
driver.get("http://localhost:8080/lrr/")
driver.maximize_window()
wait = WebDriverWait(driver, 10)
# Login as a Lecturer
username_input = wait.until(EC.presence_of_element_located((By.NAME, "user")))
password_input = driver.find_element(By.NAME, "password")
login_button = driver.find_element(By.ID, "login_btn")
username_input.send_keys("ashly@qq.com")
password_input.send_keys("admin123")
time.sleep(5)
login_button.click()
course_but= driver.find_element(By.XPATH, "(//div[@class='btn btn-default'])[1]") # Adjust this XPATH as needed
# Click on the alert
course_but.click()
time.sleep(5)
marked_tab = wait.until(
EC.element_to_be_clickable((By.XPATH, "//a[text()='Marked']"))
)
marked_tab.click()
# Wait for the Marked tab content to be present
marked_tab_content = wait.until(
EC.presence_of_element_located((By.XPATH, "//div[@id='menu4' and contains(@class, 'active')]"))
)
time.sleep(5)
remark_but = wait.until(
EC.presence_of_element_located((By.XPATH, "//button[normalize-space()='Request remarking']"))
)
remark_but.click()
time.sleep(2)
# Switch to the alert
alert = driver.switch_to.alert
# Send keys to the prompt
alert.send_keys("Number 2 was correct")
# Accept the prompt (click OK)
alert.accept()
time.sleep(5)
except NoSuchElementException as e:
print("NoSuchElementException: Could not find an element.")
traceback.print_exc()
except TimeoutException as e:
print("TimeoutException: An element took too long to load.")
traceback.print_exc()
except Exception as e:
print(f"An unexpected error occurred: {e}")
traceback.print_exc()
finally:
driver.quit()