Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58445b2a48 | |||
| 0f8a1fa0b1 | |||
| fee07bcceb | |||
| 70a6e2c104 | |||
| 11c93d3e82 | |||
| 7c5028a76d |
@@ -63,7 +63,7 @@ session.expiration = 43200
|
|||||||
database.default.hostname = 127.0.0.1
|
database.default.hostname = 127.0.0.1
|
||||||
database.default.database = school
|
database.default.database = school
|
||||||
database.default.username = root
|
database.default.username = root
|
||||||
database.default.password =
|
database.default.password = rootpassword
|
||||||
database.default.DBDriver = MySQLi
|
database.default.DBDriver = MySQLi
|
||||||
database.default.DBPrefix =
|
database.default.DBPrefix =
|
||||||
database.default.port = 3306
|
database.default.port = 3306
|
||||||
|
|||||||
+46
-38
@@ -9,43 +9,51 @@ class Database extends Config
|
|||||||
public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
|
public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
|
||||||
public string $defaultGroup = 'default';
|
public string $defaultGroup = 'default';
|
||||||
|
|
||||||
public array $default = [
|
public array $default = [];
|
||||||
'DSN' => '',
|
public array $tests = [];
|
||||||
'hostname' => 'localhost',
|
|
||||||
'username' => 'u280815660_melabidi',
|
|
||||||
'password' => '>tNxlRzP/W8',
|
|
||||||
'database' => 'u280815660_school',
|
|
||||||
'DBDriver' => 'MySQLi',
|
|
||||||
'DBPrefix' => '',
|
|
||||||
'pConnect' => false,
|
|
||||||
'DBDebug' => (ENVIRONMENT !== 'development'),
|
|
||||||
'charset' => 'utf8',
|
|
||||||
'DBCollat' => 'utf8_general_ci',
|
|
||||||
'swapPre' => '',
|
|
||||||
'encrypt' => false,
|
|
||||||
'compress' => false,
|
|
||||||
'strictOn' => false,
|
|
||||||
'failover' => [],
|
|
||||||
'port' => 3306,
|
|
||||||
];
|
|
||||||
|
|
||||||
public array $tests = [
|
public function __construct()
|
||||||
'DSN' => '',
|
{
|
||||||
'hostname' => 'localhost',
|
parent::__construct();
|
||||||
'username' => 'u280815660_melabidi',
|
|
||||||
'password' => '>tNxlRzP/W8',
|
$this->default = [
|
||||||
'database' => 'u280815660_school',
|
'DSN' => '',
|
||||||
'DBDriver' => 'MySQLi',
|
'hostname' => env('database.default.hostname'),
|
||||||
'DBPrefix' => 'db_',
|
'username' => env('database.default.username'),
|
||||||
'pConnect' => false,
|
'password' => env('database.default.password'),
|
||||||
'DBDebug' => true,
|
'database' => env('database.default.database'),
|
||||||
'charset' => 'utf8',
|
'DBDriver' => env('database.default.DBDriver', 'MySQLi'),
|
||||||
'DBCollat' => 'utf8_general_ci',
|
'DBPrefix' => '',
|
||||||
'swapPre' => '',
|
'pConnect' => false,
|
||||||
'encrypt' => false,
|
'DBDebug' => (ENVIRONMENT !== 'development'),
|
||||||
'compress' => false,
|
'charset' => 'utf8',
|
||||||
'strictOn' => false,
|
'DBCollat' => 'utf8_general_ci',
|
||||||
'failover' => [],
|
'swapPre' => '',
|
||||||
'port' => 3306,
|
'encrypt' => false,
|
||||||
];
|
'compress' => false,
|
||||||
|
'strictOn' => false,
|
||||||
|
'failover' => [],
|
||||||
|
'port' => (int) env('database.default.port', 3306),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->tests = [
|
||||||
|
'DSN' => '',
|
||||||
|
'hostname' => env('database.tests.hostname', env('database.default.hostname')),
|
||||||
|
'username' => env('database.tests.username', env('database.default.username')),
|
||||||
|
'password' => env('database.tests.password', env('database.default.password')),
|
||||||
|
'database' => env('database.tests.database', env('database.default.database')),
|
||||||
|
'DBDriver' => env('database.tests.DBDriver', env('database.default.DBDriver', 'MySQLi')),
|
||||||
|
'DBPrefix' => env('database.tests.DBPrefix', 'db_'),
|
||||||
|
'pConnect' => false,
|
||||||
|
'DBDebug' => true,
|
||||||
|
'charset' => 'utf8',
|
||||||
|
'DBCollat' => 'utf8_general_ci',
|
||||||
|
'swapPre' => '',
|
||||||
|
'encrypt' => false,
|
||||||
|
'compress' => false,
|
||||||
|
'strictOn' => false,
|
||||||
|
'failover' => [],
|
||||||
|
'port' => (int) env('database.tests.port', env('database.default.port', 3306)),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,6 +230,10 @@ $routes->get('reset_password', 'View\UserController::resetPassword');
|
|||||||
|
|
||||||
//$routes->get('/blocked', 'View\UserController::blocked');
|
//$routes->get('/blocked', 'View\UserController::blocked');
|
||||||
|
|
||||||
|
$routes->get('confirm_authorized_user', 'View\AuthorizedUsersController::confirm');
|
||||||
|
$routes->get('set_authorized_user_password/(:num)', 'View\AuthorizedUsersController::setPassword/$1');
|
||||||
|
$routes->post('set_authorized_user_password/(:num)', 'View\AuthorizedUsersController::savePassword/$1');
|
||||||
|
|
||||||
$routes->post('assign_class_student', 'View\StudentController::assignClassStudent');
|
$routes->post('assign_class_student', 'View\StudentController::assignClassStudent');
|
||||||
$routes->post('remove_class_student', 'View\StudentController::removeClassStudent');
|
$routes->post('remove_class_student', 'View\StudentController::removeClassStudent');
|
||||||
$routes->post('administrator/remove_class_student', 'View\StudentController::removeClassStudent'); // alias to avoid 404s
|
$routes->post('administrator/remove_class_student', 'View\StudentController::removeClassStudent'); // alias to avoid 404s
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ class AuthController extends Controller
|
|||||||
// Generate a secure token for the password reset
|
// Generate a secure token for the password reset
|
||||||
helper('text');
|
helper('text');
|
||||||
$token = bin2hex(random_bytes(48));
|
$token = bin2hex(random_bytes(48));
|
||||||
|
$tokenHash = hash('sha256', $token);
|
||||||
|
|
||||||
// Calculate the expiration time for the token (1 hour from now)
|
// Calculate the expiration time for the token (1 hour from now)
|
||||||
$expires_at = Time::now()->addHours(1);
|
$expires_at = Time::now()->addHours(1);
|
||||||
@@ -477,7 +478,7 @@ class AuthController extends Controller
|
|||||||
$passwordResetModel = new PasswordResetModel();
|
$passwordResetModel = new PasswordResetModel();
|
||||||
$passwordResetModel->insert([
|
$passwordResetModel->insert([
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'token' => $token,
|
'token' => $tokenHash,
|
||||||
'created_at' => Time::now(),
|
'created_at' => Time::now(),
|
||||||
'expires_at' => $expires_at,
|
'expires_at' => $expires_at,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ use CodeIgniter\I18n\Time;
|
|||||||
|
|
||||||
class AuthorizedUsersController extends ResourceController
|
class AuthorizedUsersController extends ResourceController
|
||||||
{
|
{
|
||||||
|
private const TOKEN_TTL_HOURS = 24;
|
||||||
|
|
||||||
protected $userModel;
|
protected $userModel;
|
||||||
protected $authorizedUserModel;
|
protected $authorizedUserModel;
|
||||||
|
|
||||||
@@ -18,6 +20,30 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
$this->userModel = new UserModel();
|
$this->userModel = new UserModel();
|
||||||
$this->authorizedUserModel = new AuthorizedUserModel();
|
$this->authorizedUserModel = new AuthorizedUserModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function requireLogin()
|
||||||
|
{
|
||||||
|
if (!session()->get('is_logged_in')) {
|
||||||
|
return $this->failUnauthorized('Authentication required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function requireOwnership(array $authorizedUser)
|
||||||
|
{
|
||||||
|
$userId = (int) session()->get('user_id');
|
||||||
|
if ($userId <= 0 || (int) ($authorizedUser['user_id'] ?? 0) !== $userId) {
|
||||||
|
return $this->failForbidden('You do not have access to this resource.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hashToken(string $token): string
|
||||||
|
{
|
||||||
|
return hash('sha256', $token);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Return a list of authorized users for the logged-in main user.
|
* Return a list of authorized users for the logged-in main user.
|
||||||
*
|
*
|
||||||
@@ -25,7 +51,10 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requireLogin()) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$userId = session()->get('user_id');
|
$userId = session()->get('user_id');
|
||||||
$authorizedUsers = $this->authorizedUserModel->where('user_id', $userId)->findAll();
|
$authorizedUsers = $this->authorizedUserModel->where('user_id', $userId)->findAll();
|
||||||
|
|
||||||
@@ -40,12 +69,20 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*/
|
*/
|
||||||
public function show($id = null)
|
public function show($id = null)
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requireLogin()) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$authorizedUser = $this->authorizedUserModel->find($id);
|
$authorizedUser = $this->authorizedUserModel->find($id);
|
||||||
|
|
||||||
if (!$authorizedUser) {
|
if (!$authorizedUser) {
|
||||||
return $this->failNotFound('Authorized user not found.');
|
return $this->failNotFound('Authorized user not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($resp = $this->requireOwnership($authorizedUser)) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->respond($authorizedUser);
|
return $this->respond($authorizedUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +93,10 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requireLogin()) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$email = strtolower($this->request->getPost('email'));
|
$email = strtolower($this->request->getPost('email'));
|
||||||
|
|
||||||
// Validate email
|
// Validate email
|
||||||
@@ -66,19 +107,20 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
$user = $this->userModel->where('email', $email)->first();
|
$user = $this->userModel->where('email', $email)->first();
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return $this->failNotFound('No user found with this email.');
|
return $this->respondCreated(['message' => 'Authorized user added. A confirmation email has been sent.']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a token for confirmation
|
// Generate a token for confirmation
|
||||||
helper('text');
|
helper('text');
|
||||||
$token = bin2hex(random_bytes(48));
|
$token = bin2hex(random_bytes(48));
|
||||||
|
$tokenHash = $this->hashToken($token);
|
||||||
|
|
||||||
// Add entry to the authorized_users table
|
// Add entry to the authorized_users table
|
||||||
$this->authorizedUserModel->insert([
|
$this->authorizedUserModel->insert([
|
||||||
'user_id' => session()->get('user_id'), // Main user ID
|
'user_id' => session()->get('user_id'), // Main user ID
|
||||||
'authorized_user_id' => $user['id'],
|
'authorized_user_id' => $user['id'],
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'token' => $token,
|
'token' => $tokenHash,
|
||||||
'status' => 'Pending'
|
'status' => 'Pending'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -96,6 +138,10 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*/
|
*/
|
||||||
public function update($id = null)
|
public function update($id = null)
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requireLogin()) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch the authorized user
|
// Fetch the authorized user
|
||||||
$authorizedUser = $this->authorizedUserModel->find($id);
|
$authorizedUser = $this->authorizedUserModel->find($id);
|
||||||
|
|
||||||
@@ -103,6 +149,10 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
return $this->failNotFound('Authorized user not found.');
|
return $this->failNotFound('Authorized user not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($resp = $this->requireOwnership($authorizedUser)) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the authorized user’s information (e.g., email)
|
// Update the authorized user’s information (e.g., email)
|
||||||
$email = strtolower($this->request->getPost('email'));
|
$email = strtolower($this->request->getPost('email'));
|
||||||
if ($email && filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
if ($email && filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
@@ -122,12 +172,20 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*/
|
*/
|
||||||
public function delete($id = null)
|
public function delete($id = null)
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requireLogin()) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$authorizedUser = $this->authorizedUserModel->find($id);
|
$authorizedUser = $this->authorizedUserModel->find($id);
|
||||||
|
|
||||||
if (!$authorizedUser) {
|
if (!$authorizedUser) {
|
||||||
return $this->failNotFound('Authorized user not found.');
|
return $this->failNotFound('Authorized user not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($resp = $this->requireOwnership($authorizedUser)) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the authorized user record
|
// Delete the authorized user record
|
||||||
$this->authorizedUserModel->delete($id);
|
$this->authorizedUserModel->delete($id);
|
||||||
|
|
||||||
@@ -147,16 +205,28 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
return $this->fail('Invalid confirmation link.');
|
return $this->fail('Invalid confirmation link.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$authorizedUser = $this->authorizedUserModel->where('token', $token)->first();
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$authorizedUser = $this->authorizedUserModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->where('created_at >=', Time::now()->subHours(self::TOKEN_TTL_HOURS)->toDateTimeString())
|
||||||
|
->first();
|
||||||
|
|
||||||
if (!$authorizedUser) {
|
if (!$authorizedUser) {
|
||||||
return $this->fail('Invalid or expired confirmation link.');
|
return $this->fail('Invalid or expired confirmation link.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the authorized user as active
|
// Mark the authorized user as active and rotate token for password setup
|
||||||
$this->authorizedUserModel->update($authorizedUser['id'], ['status' => 'Active', 'token' => null]);
|
$nextToken = bin2hex(random_bytes(48));
|
||||||
|
$nextTokenHash = $this->hashToken($nextToken);
|
||||||
|
$this->authorizedUserModel->update($authorizedUser['id'], [
|
||||||
|
'status' => 'Active',
|
||||||
|
'token' => $nextTokenHash,
|
||||||
|
]);
|
||||||
|
|
||||||
return redirect()->to('/set_authorized_user_password/' . $authorizedUser['authorized_user_id']);
|
return redirect()->to('/set_authorized_user_password/' . $authorizedUser['authorized_user_id'] . '?token=' . $nextToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,13 +237,36 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*/
|
*/
|
||||||
public function setPassword($authorizedUserId)
|
public function setPassword($authorizedUserId)
|
||||||
{
|
{
|
||||||
|
$token = (string) $this->request->getGet('token');
|
||||||
|
if ($token === '') {
|
||||||
|
return $this->fail('Invalid confirmation link.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$authorizedUser = $this->authorizedUserModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->where('authorized_user_id', $authorizedUserId)
|
||||||
|
->where('status', 'Active')
|
||||||
|
->where('updated_at >=', Time::now()->subHours(self::TOKEN_TTL_HOURS)->toDateTimeString())
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$authorizedUser) {
|
||||||
|
return $this->fail('Invalid or expired confirmation link.');
|
||||||
|
}
|
||||||
|
|
||||||
$user = $this->userModel->find($authorizedUserId);
|
$user = $this->userModel->find($authorizedUserId);
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return $this->failNotFound('User not found.');
|
return $this->failNotFound('User not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('user/set_authorized_user_password', ['userId' => $authorizedUserId]);
|
return view('user/set_authorized_user_password', [
|
||||||
|
'userId' => $authorizedUserId,
|
||||||
|
'token' => $token,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,38 +274,59 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
*
|
*
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
/*
|
public function savePassword($authorizedUserId = null)
|
||||||
public function savePassword()
|
|
||||||
{
|
{
|
||||||
// Validate the request
|
|
||||||
$validation = \Config\Services::validation();
|
$validation = \Config\Services::validation();
|
||||||
$validation->setRules([
|
$validation->setRules([
|
||||||
'password' => 'required|min_length[6]',
|
'password' => [
|
||||||
|
'label' => 'Password',
|
||||||
|
'rules' => 'required|min_length[8]|regex_match[/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@\\-=\\+*#$%&!?])[A-Za-z\\d@\\-=\\+*#$%&!?]{8,}$/]',
|
||||||
|
],
|
||||||
'password_confirm' => 'required|matches[password]',
|
'password_confirm' => 'required|matches[password]',
|
||||||
'user_id' => 'required|integer'
|
'user_id' => 'required|integer',
|
||||||
|
'token' => 'required',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!$this->validate($validation->getRules())) {
|
if (!$this->validate($validation->getRules())) {
|
||||||
return $this->failValidationErrors($validation->getErrors());
|
return $this->failValidationErrors($validation->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the validated input
|
$userId = (int) $this->request->getPost('user_id');
|
||||||
$userId = $this->request->getPost('user_id');
|
$token = (string) $this->request->getPost('token');
|
||||||
$password = $this->request->getPost('password');
|
$authorizedUserId = $authorizedUserId !== null ? (int) $authorizedUserId : $userId;
|
||||||
|
|
||||||
$model = new UserModel();
|
if ($userId <= 0 || $authorizedUserId <= 0 || $userId !== $authorizedUserId) {
|
||||||
$user = $model->find($userId);
|
return $this->fail('Invalid request.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$authorizedUser = $this->authorizedUserModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->where('authorized_user_id', $authorizedUserId)
|
||||||
|
->where('status', 'Active')
|
||||||
|
->where('updated_at >=', Time::now()->subHours(self::TOKEN_TTL_HOURS)->toDateTimeString())
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$authorizedUser) {
|
||||||
|
return $this->fail('Invalid or expired confirmation link.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->userModel->find($authorizedUserId);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return $this->failNotFound('User not found.');
|
return $this->failNotFound('User not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the password
|
$password = (string) $this->request->getPost('password');
|
||||||
$model->update($userId, ['password' => password_hash($password, PASSWORD_DEFAULT)]);
|
$hashedPassword = pbkdf2_hash($password);
|
||||||
|
|
||||||
|
$this->userModel->update($authorizedUserId, ['password' => $hashedPassword]);
|
||||||
|
$this->authorizedUserModel->update($authorizedUser['id'], ['token' => null]);
|
||||||
|
|
||||||
return $this->respond(['message' => 'Password has been successfully set.']);
|
return $this->respond(['message' => 'Password has been successfully set.']);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Sends a confirmation email to the authorized user.
|
* Sends a confirmation email to the authorized user.
|
||||||
*
|
*
|
||||||
@@ -242,4 +356,4 @@ class AuthorizedUsersController extends ResourceController
|
|||||||
log_message('error', 'Failed to send authorized user confirmation email to ' . $email);
|
log_message('error', 'Failed to send authorized user confirmation email to ' . $email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1283,10 +1283,11 @@ public function financialReport()
|
|||||||
$parentIds = array_values(array_unique(array_map(static fn($r) => (int)($r['parent_id'] ?? 0), $rows)));
|
$parentIds = array_values(array_unique(array_map(static fn($r) => (int)($r['parent_id'] ?? 0), $rows)));
|
||||||
$hasPayments = [];
|
$hasPayments = [];
|
||||||
$paidTotals = [];
|
$paidTotals = [];
|
||||||
|
$paymentCounts = [];
|
||||||
if (!empty($parentIds)) {
|
if (!empty($parentIds)) {
|
||||||
try {
|
try {
|
||||||
$pRows = $db->table('payments')
|
$pRows = $db->table('payments')
|
||||||
->select('parent_id, SUM(paid_amount) AS total_paid')
|
->select('parent_id, SUM(paid_amount) AS total_paid, COUNT(*) AS payment_count')
|
||||||
->whereIn('parent_id', $parentIds)
|
->whereIn('parent_id', $parentIds)
|
||||||
->where('school_year', $schoolYear)
|
->where('school_year', $schoolYear)
|
||||||
->groupBy('parent_id')
|
->groupBy('parent_id')
|
||||||
@@ -1296,6 +1297,7 @@ public function financialReport()
|
|||||||
if ($pid > 0) {
|
if ($pid > 0) {
|
||||||
$hasPayments[$pid] = true;
|
$hasPayments[$pid] = true;
|
||||||
$paidTotals[$pid] = (float)($pr['total_paid'] ?? 0);
|
$paidTotals[$pid] = (float)($pr['total_paid'] ?? 0);
|
||||||
|
$paymentCounts[$pid] = (int)($pr['payment_count'] ?? 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@@ -1303,7 +1305,7 @@ public function financialReport()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$dataRows = array_map(function(array $r) use ($hasPayments, $paidTotals, $nextInstallmentYmd) {
|
$dataRows = array_map(function(array $r) use ($hasPayments, $paidTotals, $paymentCounts, $nextInstallmentYmd) {
|
||||||
$pid = (int)($r['parent_id'] ?? 0);
|
$pid = (int)($r['parent_id'] ?? 0);
|
||||||
$name = trim((string)($r['firstname'] ?? '') . ' ' . (string)($r['lastname'] ?? ''));
|
$name = trim((string)($r['firstname'] ?? '') . ' ' . (string)($r['lastname'] ?? ''));
|
||||||
return [
|
return [
|
||||||
@@ -1317,6 +1319,7 @@ public function financialReport()
|
|||||||
'installment_amount' => (float)($r['installment_amount'] ?? 0),
|
'installment_amount' => (float)($r['installment_amount'] ?? 0),
|
||||||
'type' => isset($hasPayments[$pid]) ? 'installment' : 'no_payment',
|
'type' => isset($hasPayments[$pid]) ? 'installment' : 'no_payment',
|
||||||
'total_paid' => isset($paidTotals[$pid]) ? (float)$paidTotals[$pid] : 0.0,
|
'total_paid' => isset($paidTotals[$pid]) ? (float)$paidTotals[$pid] : 0.0,
|
||||||
|
'payment_count' => isset($paymentCounts[$pid]) ? (int)$paymentCounts[$pid] : 0,
|
||||||
'has_installment'=> isset($hasPayments[$pid]) ? 1 : 0,
|
'has_installment'=> isset($hasPayments[$pid]) ? 1 : 0,
|
||||||
'next_installment' => $nextInstallmentYmd,
|
'next_installment' => $nextInstallmentYmd,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -421,17 +421,45 @@ class FlagController extends Controller
|
|||||||
log_message('debug', 'Flag state: ' . $this->request->getPost('flag_state'));
|
log_message('debug', 'Flag state: ' . $this->request->getPost('flag_state'));
|
||||||
|
|
||||||
$currentFlagModel = new CurrentFlagModel();
|
$currentFlagModel = new CurrentFlagModel();
|
||||||
|
$userId = session()->get('user_id');
|
||||||
|
|
||||||
// Get the new flag state from the form
|
// Get the new flag state from the form
|
||||||
$newState = $this->request->getPost('flag_state');
|
$newState = $this->request->getPost('flag_state');
|
||||||
|
$stateDescription = (string) ($this->request->getPost('state_description') ?? '');
|
||||||
|
$actionTaken = (string) ($this->request->getPost('action_taken') ?? '');
|
||||||
|
|
||||||
if (!$newState) {
|
if (!$newState) {
|
||||||
session()->setFlashdata('error', 'incident state not provided.');
|
session()->setFlashdata('error', 'incident state not provided.');
|
||||||
return $this->index();
|
return $this->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$update = ['flag_state' => $newState];
|
||||||
|
if ($newState === 'Closed') {
|
||||||
|
$update['updated_by_closed'] = $userId;
|
||||||
|
if ($stateDescription !== '') {
|
||||||
|
$update['close_description'] = $stateDescription;
|
||||||
|
}
|
||||||
|
if ($actionTaken !== '') {
|
||||||
|
$update['action_taken'] = $actionTaken;
|
||||||
|
}
|
||||||
|
} elseif ($newState === 'Canceled') {
|
||||||
|
$update['updated_by_canceled'] = $userId;
|
||||||
|
if ($stateDescription !== '') {
|
||||||
|
$update['cancel_description'] = $stateDescription;
|
||||||
|
}
|
||||||
|
if ($actionTaken !== '') {
|
||||||
|
$update['action_taken'] = $actionTaken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update the flag state in the database
|
// Update the flag state in the database
|
||||||
if ($currentFlagModel->update($id, ['flag_state' => $newState])) {
|
if ($currentFlagModel->update($id, $update)) {
|
||||||
|
if ($newState === 'Closed' || $newState === 'Canceled') {
|
||||||
|
$flagData = $currentFlagModel->find($id);
|
||||||
|
if ($flagData) {
|
||||||
|
return $this->moveToHistory($flagData);
|
||||||
|
}
|
||||||
|
}
|
||||||
session()->setFlashdata('success', 'Incident state updated successfully!');
|
session()->setFlashdata('success', 'Incident state updated successfully!');
|
||||||
} else {
|
} else {
|
||||||
$errors = $currentFlagModel->errors();
|
$errors = $currentFlagModel->errors();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ use App\Models\PlacementLevelModel;
|
|||||||
use App\Models\PlacementBatchModel;
|
use App\Models\PlacementBatchModel;
|
||||||
use App\Models\PlacementScoreModel;
|
use App\Models\PlacementScoreModel;
|
||||||
use App\Models\GradingLockModel;
|
use App\Models\GradingLockModel;
|
||||||
|
use App\Services\NavbarService;
|
||||||
|
|
||||||
//use App\Models\ScoreModel;
|
//use App\Models\ScoreModel;
|
||||||
|
|
||||||
@@ -1079,11 +1080,14 @@ class GradingController extends Controller
|
|||||||
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
||||||
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
|
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
|
||||||
|
|
||||||
|
$canViewGrading = $this->userHasMenuUrl('grading');
|
||||||
|
|
||||||
return view('grading/below_sixty', [
|
return view('grading/below_sixty', [
|
||||||
'rows' => $rows,
|
'rows' => $rows,
|
||||||
'semester' => $semester,
|
'semester' => $semester,
|
||||||
'schoolYear' => $schoolYear,
|
'schoolYear' => $schoolYear,
|
||||||
'schoolYears' => $schoolYears,
|
'schoolYears' => $schoolYears,
|
||||||
|
'canViewGrading' => $canViewGrading,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1212,6 +1216,14 @@ class GradingController extends Controller
|
|||||||
|
|
||||||
$flagModel = new CurrentFlagModel();
|
$flagModel = new CurrentFlagModel();
|
||||||
$semKey = strtolower(trim($semester));
|
$semKey = strtolower(trim($semester));
|
||||||
|
$redirectUrl = base_url('grading/below-60');
|
||||||
|
$query = http_build_query([
|
||||||
|
'semester' => $semester,
|
||||||
|
'school_year' => $schoolYear,
|
||||||
|
]);
|
||||||
|
if ($query !== '') {
|
||||||
|
$redirectUrl .= '?' . $query;
|
||||||
|
}
|
||||||
|
|
||||||
$existing = $flagModel
|
$existing = $flagModel
|
||||||
->where('student_id', $studentId)
|
->where('student_id', $studentId)
|
||||||
@@ -1222,11 +1234,14 @@ class GradingController extends Controller
|
|||||||
|
|
||||||
$userId = (int)(session()->get('user_id') ?? 0) ?: null;
|
$userId = (int)(session()->get('user_id') ?? 0) ?: null;
|
||||||
$now = utc_now();
|
$now = utc_now();
|
||||||
|
$ok = true;
|
||||||
|
|
||||||
if ($existing) {
|
if ($existing) {
|
||||||
$data = [
|
$data = [
|
||||||
'flag_state' => $status,
|
'flag_state' => $status,
|
||||||
'flag_datetime' => $now,
|
'flag_datetime' => $now,
|
||||||
|
'semester' => $semester,
|
||||||
|
'school_year' => $schoolYear,
|
||||||
'updated_at' => $now,
|
'updated_at' => $now,
|
||||||
];
|
];
|
||||||
if ($status === 'Open') {
|
if ($status === 'Open') {
|
||||||
@@ -1242,7 +1257,7 @@ class GradingController extends Controller
|
|||||||
$data['close_description'] = trim($prev . PHP_EOL . $note);
|
$data['close_description'] = trim($prev . PHP_EOL . $note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$flagModel->update((int)$existing['id'], $data);
|
$ok = (bool) $flagModel->update((int)$existing['id'], $data);
|
||||||
} else {
|
} else {
|
||||||
$row = $this->fetchBelowSixtyEmailRow($studentId, $schoolYear, $semester);
|
$row = $this->fetchBelowSixtyEmailRow($studentId, $schoolYear, $semester);
|
||||||
$studentName = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
|
$studentName = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
|
||||||
@@ -1265,10 +1280,21 @@ class GradingController extends Controller
|
|||||||
$data['updated_by_closed'] = $userId;
|
$data['updated_by_closed'] = $userId;
|
||||||
if ($note !== '') $data['close_description'] = $note;
|
if ($note !== '') $data['close_description'] = $note;
|
||||||
}
|
}
|
||||||
$flagModel->insert($data);
|
$ok = (bool) $flagModel->insert($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('status', 'Status updated.');
|
if (!$ok) {
|
||||||
|
log_message('error', 'updateBelowSixtyStatus failed', [
|
||||||
|
'student_id' => $studentId,
|
||||||
|
'semester' => $semester,
|
||||||
|
'school_year' => $schoolYear,
|
||||||
|
'status' => $status,
|
||||||
|
'errors' => $flagModel->errors(),
|
||||||
|
]);
|
||||||
|
return redirect()->to($redirectUrl)->with('error', 'Failed to update status.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to($redirectUrl)->with('status', 'Status updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scheduleBelowSixty()
|
public function scheduleBelowSixty()
|
||||||
@@ -1793,9 +1819,10 @@ class GradingController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$statusMap = [];
|
$statusMap = [];
|
||||||
|
$noteMap = [];
|
||||||
if (!empty($studentIds)) {
|
if (!empty($studentIds)) {
|
||||||
$flagRows = $this->db->table('current_flag')
|
$flagRows = $this->db->table('current_flag')
|
||||||
->select('student_id, flag_state')
|
->select('student_id, flag_state, open_description, close_description')
|
||||||
->where('flag', 'grade')
|
->where('flag', 'grade')
|
||||||
->where('school_year', $schoolYear)
|
->where('school_year', $schoolYear)
|
||||||
->where("LOWER(TRIM(semester))", $semesterKey)
|
->where("LOWER(TRIM(semester))", $semesterKey)
|
||||||
@@ -1806,6 +1833,12 @@ class GradingController extends Controller
|
|||||||
$sid = (int)($row['student_id'] ?? 0);
|
$sid = (int)($row['student_id'] ?? 0);
|
||||||
if ($sid <= 0) continue;
|
if ($sid <= 0) continue;
|
||||||
$statusMap[$sid] = (string)($row['flag_state'] ?? '');
|
$statusMap[$sid] = (string)($row['flag_state'] ?? '');
|
||||||
|
$openNote = trim((string)($row['open_description'] ?? ''));
|
||||||
|
$closeNote = trim((string)($row['close_description'] ?? ''));
|
||||||
|
$noteMap[$sid] = [
|
||||||
|
'open' => $openNote,
|
||||||
|
'closed' => $closeNote,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1814,6 +1847,15 @@ class GradingController extends Controller
|
|||||||
$row['comment'] = $commentMap[$sid] ?? '';
|
$row['comment'] = $commentMap[$sid] ?? '';
|
||||||
$flagState = strtolower(trim((string)($statusMap[$sid] ?? '')));
|
$flagState = strtolower(trim((string)($statusMap[$sid] ?? '')));
|
||||||
$row['status'] = ($flagState === 'closed' || $flagState === 'canceled') ? 'Closed' : 'Open';
|
$row['status'] = ($flagState === 'closed' || $flagState === 'canceled') ? 'Closed' : 'Open';
|
||||||
|
$noteBag = $noteMap[$sid] ?? ['open' => '', 'closed' => ''];
|
||||||
|
$rawNote = $row['status'] === 'Closed' ? (string)$noteBag['closed'] : (string)$noteBag['open'];
|
||||||
|
if ($rawNote !== '') {
|
||||||
|
$lines = preg_split('/\R/', $rawNote);
|
||||||
|
$lines = array_values(array_filter(array_map('trim', $lines), static fn($val) => $val !== ''));
|
||||||
|
$row['note'] = $lines ? end($lines) : '';
|
||||||
|
} else {
|
||||||
|
$row['note'] = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unset($row);
|
unset($row);
|
||||||
|
|
||||||
@@ -1863,6 +1905,54 @@ class GradingController extends Controller
|
|||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function userHasMenuUrl(string $needle): bool
|
||||||
|
{
|
||||||
|
$needle = strtolower(trim($needle));
|
||||||
|
if ($needle === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rawRole = session()->get('role');
|
||||||
|
$roles = is_array($rawRole) ? $rawRole : [$rawRole ?? 'guest'];
|
||||||
|
$roles = array_values(array_filter(array_map('strval', $roles)));
|
||||||
|
if (empty($roles)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$service = new NavbarService();
|
||||||
|
$menu = $service->getMenuForRoles($roles);
|
||||||
|
if (empty($menu)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalize = static function (string $url) use ($needle): string {
|
||||||
|
$url = strtolower(trim($url));
|
||||||
|
if ($url === '') return '';
|
||||||
|
$url = preg_replace('#^https?://[^/]+/#i', '', $url);
|
||||||
|
$url = ltrim($url, '/');
|
||||||
|
return $url;
|
||||||
|
};
|
||||||
|
|
||||||
|
$target = $normalize($needle);
|
||||||
|
$stack = $menu;
|
||||||
|
while (!empty($stack)) {
|
||||||
|
$node = array_shift($stack);
|
||||||
|
if (!empty($node['url'])) {
|
||||||
|
$url = $normalize((string)$node['url']);
|
||||||
|
if ($url !== '' && $url === $target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($node['children']) && is_array($node['children'])) {
|
||||||
|
foreach ($node['children'] as $child) {
|
||||||
|
$stack[] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private function fetchBelowSixtyParentName(int $studentId): string
|
private function fetchBelowSixtyParentName(int $studentId): string
|
||||||
{
|
{
|
||||||
$parentName = 'Parent/Guardian';
|
$parentName = 'Parent/Guardian';
|
||||||
|
|||||||
@@ -717,6 +717,7 @@ class ParentController extends BaseController
|
|||||||
|
|
||||||
// Step 1: Generate a secure token for email verification
|
// Step 1: Generate a secure token for email verification
|
||||||
$token = bin2hex(random_bytes(48));
|
$token = bin2hex(random_bytes(48));
|
||||||
|
$tokenHash = hash('sha256', $token);
|
||||||
|
|
||||||
// Step 2: Determine user type based on relationship
|
// Step 2: Determine user type based on relationship
|
||||||
$userType = in_array(strtolower($relationToStudent), ['wife', 'husband']) ? 'Secondary' : 'Tertiary';
|
$userType = in_array(strtolower($relationToStudent), ['wife', 'husband']) ? 'Secondary' : 'Tertiary';
|
||||||
@@ -776,7 +777,7 @@ class ParentController extends BaseController
|
|||||||
'state' => strtoupper($userData['state']),
|
'state' => strtoupper($userData['state']),
|
||||||
'zip' => $userData['zip'],
|
'zip' => $userData['zip'],
|
||||||
'accept_school_policy' => $userData['accept_school_policy'] ?? 0,
|
'accept_school_policy' => $userData['accept_school_policy'] ?? 0,
|
||||||
'token' => $token,
|
'token' => $tokenHash,
|
||||||
'is_verified' => 0,
|
'is_verified' => 0,
|
||||||
'status' => 'Inactive',
|
'status' => 'Inactive',
|
||||||
'user_type' => $userType,
|
'user_type' => $userType,
|
||||||
|
|||||||
@@ -173,16 +173,8 @@ class RegisterController extends Controller
|
|||||||
$existingUser = $this->userModel->where('email', $post['email'])->first();
|
$existingUser = $this->userModel->where('email', $post['email'])->first();
|
||||||
|
|
||||||
if ($existingUser) {
|
if ($existingUser) {
|
||||||
// Step 2: Check if the user has a token (i.e., not verified yet)
|
return redirect()->back()->withInput()->with('error',
|
||||||
if (!empty($existingUser['token']) && $existingUser['is_verified'] == 0) {
|
'This email address is already registered. Please check your email or log in.');
|
||||||
// User exists and is unverified
|
|
||||||
return redirect()->back()->withInput()->with('error',
|
|
||||||
'This email address is already registered and is pending activation. Please check your email to activate your account.');
|
|
||||||
} else {
|
|
||||||
// User exists and is already active or has no token
|
|
||||||
return redirect()->back()->withInput()->with('error',
|
|
||||||
'The email address you entered is already in use. Please try a different one.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ───────────── 6. Determine role ───────────── */
|
/* ───────────── 6. Determine role ───────────── */
|
||||||
@@ -194,6 +186,7 @@ class RegisterController extends Controller
|
|||||||
|
|
||||||
/* ───────────── 7. Build & insert user ───────────── */
|
/* ───────────── 7. Build & insert user ───────────── */
|
||||||
$token = bin2hex(random_bytes(48));
|
$token = bin2hex(random_bytes(48));
|
||||||
|
$tokenHash = hash('sha256', $token);
|
||||||
$userData = [
|
$userData = [
|
||||||
'firstname' => $post['firstname'],
|
'firstname' => $post['firstname'],
|
||||||
'lastname' => $post['lastname'],
|
'lastname' => $post['lastname'],
|
||||||
@@ -205,7 +198,7 @@ class RegisterController extends Controller
|
|||||||
'city' => $post['city'],
|
'city' => $post['city'],
|
||||||
'state' => $post['state'],
|
'state' => $post['state'],
|
||||||
'zip' => $post['zip'],
|
'zip' => $post['zip'],
|
||||||
'token' => $token,
|
'token' => $tokenHash,
|
||||||
'is_verified'=> 0,
|
'is_verified'=> 0,
|
||||||
'accept_school_policy' => (int) $post['accept_school_policy'],
|
'accept_school_policy' => (int) $post['accept_school_policy'],
|
||||||
'status' => 'Inactive',
|
'status' => 'Inactive',
|
||||||
@@ -357,4 +350,4 @@ class RegisterController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ class SubjectCurriculumController extends BaseController
|
|||||||
->orderBy('classes.class_name', 'ASC')
|
->orderBy('classes.class_name', 'ASC')
|
||||||
->orderBy('subject', 'ASC')
|
->orderBy('subject', 'ASC')
|
||||||
->orderBy('unit_number', 'ASC')
|
->orderBy('unit_number', 'ASC')
|
||||||
|
->orderBy("CAST(SUBSTRING_INDEX(subject_curriculum_items.chapter_name, '.', 1) AS UNSIGNED)", 'ASC', false)
|
||||||
->orderBy('chapter_name', 'ASC')
|
->orderBy('chapter_name', 'ASC')
|
||||||
->get()
|
->get()
|
||||||
->getResultArray();
|
->getResultArray();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ require_once APPPATH . 'Helpers/pbkdf2_helper.php';
|
|||||||
|
|
||||||
class UserController extends BaseController
|
class UserController extends BaseController
|
||||||
{
|
{
|
||||||
|
private const ACTIVATION_TTL_HOURS = 48;
|
||||||
protected $userModel;
|
protected $userModel;
|
||||||
protected $roleModel;
|
protected $roleModel;
|
||||||
protected $userRoleModel;
|
protected $userRoleModel;
|
||||||
@@ -49,6 +50,37 @@ class UserController extends BaseController
|
|||||||
$this->resetRequestModel = new PasswordResetRequestModel();
|
$this->resetRequestModel = new PasswordResetRequestModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function denyAccess(string $message)
|
||||||
|
{
|
||||||
|
if ($this->request->isAJAX() || $this->request->getHeaderLine('Accept') === 'application/json') {
|
||||||
|
return service('response')
|
||||||
|
->setStatusCode(403)
|
||||||
|
->setJSON(['status' => 'error', 'message' => $message]);
|
||||||
|
}
|
||||||
|
|
||||||
|
session()->setFlashdata('error', $message);
|
||||||
|
return redirect()->to('/access_denied');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function requirePermission(string $permission)
|
||||||
|
{
|
||||||
|
if (!session()->get('is_logged_in')) {
|
||||||
|
return redirect()->to('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$userId = (int) session()->get('user_id');
|
||||||
|
if ($userId <= 0 || !has_permission($userId, $permission)) {
|
||||||
|
return $this->denyAccess("You don't have permission to use this feature.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hashToken(string $token): string
|
||||||
|
{
|
||||||
|
return hash('sha256', $token);
|
||||||
|
}
|
||||||
|
|
||||||
// Method to show the home page
|
// Method to show the home page
|
||||||
public function home()
|
public function home()
|
||||||
{
|
{
|
||||||
@@ -75,6 +107,10 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function userList()
|
public function userList()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('read_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
helper('url');
|
helper('url');
|
||||||
|
|
||||||
return view('user/user_list', [
|
return view('user/user_list', [
|
||||||
@@ -85,6 +121,10 @@ class UserController extends BaseController
|
|||||||
// Method to show the list of users
|
// Method to show the list of users
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('read_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch users along with their assigned roles
|
// Fetch users along with their assigned roles
|
||||||
$builder = $this->db->table('users');
|
$builder = $this->db->table('users');
|
||||||
$builder->select('users.id, users.firstname, users.lastname, users.email, user_roles.role_id, roles.name as role, users.status, users.updated_at');
|
$builder->select('users.id, users.firstname, users.lastname, users.email, user_roles.role_id, roles.name as role, users.status, users.updated_at');
|
||||||
@@ -122,6 +162,10 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function userListData()
|
public function userListData()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('read_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'users' => $this->buildUsersWithRoles(),
|
'users' => $this->buildUsersWithRoles(),
|
||||||
]);
|
]);
|
||||||
@@ -253,6 +297,10 @@ class UserController extends BaseController
|
|||||||
// Method to store a new user
|
// Method to store a new user
|
||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('edit_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate input data
|
// Validate input data
|
||||||
$validation = \Config\Services::validation();
|
$validation = \Config\Services::validation();
|
||||||
$validation->setRules([
|
$validation->setRules([
|
||||||
@@ -315,6 +363,10 @@ class UserController extends BaseController
|
|||||||
// Method to show the form for editing an existing user
|
// Method to show the form for editing an existing user
|
||||||
public function edit($id)
|
public function edit($id)
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('edit_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$data['user'] = $this->userModel->find($id);
|
$data['user'] = $this->userModel->find($id);
|
||||||
$data['roles'] = $this->roleModel->findAll();
|
$data['roles'] = $this->roleModel->findAll();
|
||||||
$userRoles = $this->userRoleModel->where('user_id', $id)->findAll();
|
$userRoles = $this->userRoleModel->where('user_id', $id)->findAll();
|
||||||
@@ -327,6 +379,10 @@ class UserController extends BaseController
|
|||||||
// Method to delete an existing user
|
// Method to delete an existing user
|
||||||
public function delete($id)
|
public function delete($id)
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('edit_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$this->userModel->delete($id);
|
$this->userModel->delete($id);
|
||||||
|
|
||||||
// Delete the user's roles from the user_roles table
|
// Delete the user's roles from the user_roles table
|
||||||
@@ -369,27 +425,21 @@ class UserController extends BaseController
|
|||||||
$email = strtolower($this->request->getPost('email'));
|
$email = strtolower($this->request->getPost('email'));
|
||||||
$user = $this->userModel->where('email', $email)->first();
|
$user = $this->userModel->where('email', $email)->first();
|
||||||
|
|
||||||
// --- Handle unknown email ---
|
// --- Handle unknown or unverified email ---
|
||||||
if (!$user) {
|
if (!$user || (int) $user['is_verified'] === 0) {
|
||||||
session()->setFlashdata('error', 'If this email is registered, you will receive a reset link.');
|
session()->setFlashdata('success', 'If this email is registered, you will receive a reset link.');
|
||||||
log_message('info', "Password reset requested for non-existing user {$email}");
|
log_message('info', "Password reset requested for {$email} (user missing or unverified).");
|
||||||
return redirect()->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Handle unverified accounts ---
|
|
||||||
if ((int) $user['is_verified'] === 0) {
|
|
||||||
session()->setFlashdata('error', 'Please check your email and complete the account activation process before resetting your password.');
|
|
||||||
log_message('info', "Password reset blocked for unverified user {$email}");
|
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Verified user: continue with reset ---
|
// --- Verified user: continue with reset ---
|
||||||
$token = bin2hex(random_bytes(48));
|
$token = bin2hex(random_bytes(48));
|
||||||
|
$tokenHash = $this->hashToken($token);
|
||||||
$expires_at = Time::now()->addHours(1);
|
$expires_at = Time::now()->addHours(1);
|
||||||
|
|
||||||
$this->passwordResetModel->insert([
|
$this->passwordResetModel->insert([
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'token' => $token,
|
'token' => $tokenHash,
|
||||||
'created_at' => Time::now(),
|
'created_at' => Time::now(),
|
||||||
'expires_at' => $expires_at,
|
'expires_at' => $expires_at,
|
||||||
]);
|
]);
|
||||||
@@ -447,7 +497,12 @@ class UserController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// You may want to validate the token here
|
// You may want to validate the token here
|
||||||
$resetEntry = $this->passwordResetModel->where('token', $token)
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$resetEntry = $this->passwordResetModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
->where('expires_at >=', Time::now())
|
->where('expires_at >=', Time::now())
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
@@ -462,6 +517,10 @@ class UserController extends BaseController
|
|||||||
//This function processes the new password submission, validating the token, updating the user's password, and cleaning up the reset entry.
|
//This function processes the new password submission, validating the token, updating the user's password, and cleaning up the reset entry.
|
||||||
public function processResetPassword()
|
public function processResetPassword()
|
||||||
{
|
{
|
||||||
|
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||||
|
return redirect()->to('/')->with('error', 'Invalid request.');
|
||||||
|
}
|
||||||
|
|
||||||
$token = $this->request->getPost('token');
|
$token = $this->request->getPost('token');
|
||||||
$newPassword = $this->request->getPost('password');
|
$newPassword = $this->request->getPost('password');
|
||||||
$passConfirm = $this->request->getPost('pass_confirm');
|
$passConfirm = $this->request->getPost('pass_confirm');
|
||||||
@@ -490,7 +549,12 @@ class UserController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the password reset entry
|
// Find the password reset entry
|
||||||
$resetEntry = $this->passwordResetModel->where('token', $token)
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$resetEntry = $this->passwordResetModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
->where('expires_at >=', Time::now())
|
->where('expires_at >=', Time::now())
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
@@ -519,7 +583,12 @@ class UserController extends BaseController
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Delete the used token from the password reset table
|
// Delete the used token from the password reset table
|
||||||
$this->passwordResetModel->where('token', $token)->delete();
|
$this->passwordResetModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->delete();
|
||||||
|
|
||||||
// Retrieve the user's IP address from the request
|
// Retrieve the user's IP address from the request
|
||||||
$ipAddress = $this->request->getIPAddress();
|
$ipAddress = $this->request->getIPAddress();
|
||||||
@@ -546,10 +615,16 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function confirm($token)
|
public function confirm($token)
|
||||||
{
|
{
|
||||||
log_message('info', 'Processing email confirmation with token: ' . $token);
|
log_message('info', 'Processing email confirmation.');
|
||||||
|
|
||||||
|
$tokenHash = $this->hashToken($token);
|
||||||
$user = $this->userModel->where('token', $token)->first();
|
$user = $this->userModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->where('created_at >=', Time::now()->subHours(self::ACTIVATION_TTL_HOURS)->toDateTimeString())
|
||||||
|
->first();
|
||||||
|
|
||||||
if (!$user || $user['is_verified'] == 1) {
|
if (!$user || $user['is_verified'] == 1) {
|
||||||
return redirect()->to('/invalid_token');
|
return redirect()->to('/invalid_token');
|
||||||
@@ -570,7 +645,14 @@ class UserController extends BaseController
|
|||||||
{
|
{
|
||||||
//echo "Reached setPassword with token: " . esc($token);
|
//echo "Reached setPassword with token: " . esc($token);
|
||||||
//echo "Token received: " . $token;
|
//echo "Token received: " . $token;
|
||||||
$user = $this->userModel->where('token', $token)->first();
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$user = $this->userModel
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->where('created_at >=', Time::now()->subHours(self::ACTIVATION_TTL_HOURS)->toDateTimeString())
|
||||||
|
->first();
|
||||||
|
|
||||||
if (!$user || $user['is_verified'] == 1) {
|
if (!$user || $user['is_verified'] == 1) {
|
||||||
return redirect()->to('/invalid_token');
|
return redirect()->to('/invalid_token');
|
||||||
@@ -584,6 +666,10 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function savePassword()
|
public function savePassword()
|
||||||
{
|
{
|
||||||
|
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||||
|
return redirect()->to('/')->with('error', 'Invalid request.');
|
||||||
|
}
|
||||||
|
|
||||||
$validation = \Config\Services::validation();
|
$validation = \Config\Services::validation();
|
||||||
$validation->setRules([
|
$validation->setRules([
|
||||||
'password' => [
|
'password' => [
|
||||||
@@ -615,9 +701,17 @@ class UserController extends BaseController
|
|||||||
$token = $this->request->getPost('token');
|
$token = $this->request->getPost('token');
|
||||||
$password = $this->request->getPost('password');
|
$password = $this->request->getPost('password');
|
||||||
|
|
||||||
$user = $this->userModel->where('id', $userId)->where('token', $token)->first();
|
$tokenHash = $this->hashToken($token);
|
||||||
|
$user = $this->userModel
|
||||||
|
->where('id', $userId)
|
||||||
|
->groupStart()
|
||||||
|
->where('token', $tokenHash)
|
||||||
|
->orWhere('token', $token)
|
||||||
|
->groupEnd()
|
||||||
|
->where('created_at >=', Time::now()->subHours(self::ACTIVATION_TTL_HOURS)->toDateTimeString())
|
||||||
|
->first();
|
||||||
|
|
||||||
log_message('debug', "Attempting to set password for user $userId with token $token");
|
log_message('debug', "Attempting to set password for user $userId");
|
||||||
|
|
||||||
if (!$user || $user['is_verified'] == 1) {
|
if (!$user || $user['is_verified'] == 1) {
|
||||||
return redirect()->to('/invalid_token');
|
return redirect()->to('/invalid_token');
|
||||||
@@ -670,20 +764,39 @@ class UserController extends BaseController
|
|||||||
$roleKey = (string) $this->request->getPost('role');
|
$roleKey = (string) $this->request->getPost('role');
|
||||||
log_message('info', 'Role selected: ' . $roleKey);
|
log_message('info', 'Role selected: ' . $roleKey);
|
||||||
|
|
||||||
$roleModel = new RoleModel();
|
|
||||||
$route = $roleModel->getRouteByNameOrSlug($roleKey);
|
|
||||||
|
|
||||||
if ($route === null) {
|
|
||||||
log_message('error', 'Invalid or inactive role selected: ' . $roleKey);
|
|
||||||
return redirect()->back()->with('error', 'Invalid role selected.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$userId = (int) session()->get('user_id');
|
$userId = (int) session()->get('user_id');
|
||||||
log_message('info', 'User ID: ' . $userId);
|
log_message('info', 'User ID: ' . $userId);
|
||||||
|
|
||||||
|
if ($userId <= 0) {
|
||||||
|
return $this->denyAccess("You don't have permission to use this feature.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$roleRow = $this->db->table('user_roles ur')
|
||||||
|
->join('roles r', 'r.id = ur.role_id', 'inner')
|
||||||
|
->select('r.name, r.slug, r.dashboard_route')
|
||||||
|
->where('ur.user_id', $userId)
|
||||||
|
->where('r.is_active', 1)
|
||||||
|
->groupStart()
|
||||||
|
->where('LOWER(r.name)', strtolower($roleKey))
|
||||||
|
->orWhere('LOWER(r.slug)', strtolower($roleKey))
|
||||||
|
->groupEnd()
|
||||||
|
->get()
|
||||||
|
->getRowArray();
|
||||||
|
|
||||||
|
if (empty($roleRow)) {
|
||||||
|
log_message('error', 'Invalid or unassigned role selected: ' . $roleKey);
|
||||||
|
return redirect()->back()->with('error', 'Invalid role selected.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$route = $roleRow['dashboard_route'] ?? null;
|
||||||
|
if ($route === null) {
|
||||||
|
log_message('error', 'No dashboard route configured for role: ' . $roleKey);
|
||||||
|
return redirect()->back()->with('error', 'Invalid role selected.');
|
||||||
|
}
|
||||||
|
|
||||||
// Persist the *exact* role name or slug—choose your convention.
|
// Persist the *exact* role name or slug—choose your convention.
|
||||||
// If you want to store the canonical name, fetch the row and use $row['name'].
|
// Store the canonical name to avoid arbitrary role strings.
|
||||||
$this->userModel->update($userId, ['role' => $roleKey]);
|
$this->userModel->update($userId, ['role' => $roleRow['name']]);
|
||||||
log_message('info', 'Role updated in database.');
|
log_message('info', 'Role updated in database.');
|
||||||
|
|
||||||
log_message('info', 'Redirecting to role dashboard: ' . $route);
|
log_message('info', 'Redirecting to role dashboard: ' . $route);
|
||||||
@@ -702,6 +815,10 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function delete_role($roleId)
|
public function delete_role($roleId)
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('edit_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch the role to be deleted
|
// Fetch the role to be deleted
|
||||||
$role = $this->roleModel->find($roleId);
|
$role = $this->roleModel->find($roleId);
|
||||||
if (!$role) {
|
if (!$role) {
|
||||||
@@ -731,6 +848,10 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function loginActivity()
|
public function loginActivity()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('view_login_activity')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
helper('url');
|
helper('url');
|
||||||
|
|
||||||
$perPage = (int) ($this->request->getGet('per_page') ?? 25);
|
$perPage = (int) ($this->request->getGet('per_page') ?? 25);
|
||||||
@@ -743,6 +864,10 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
public function loginActivityData()
|
public function loginActivityData()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('view_login_activity')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
$perPage = (int) ($this->request->getGet('per_page') ?? 25);
|
$perPage = (int) ($this->request->getGet('per_page') ?? 25);
|
||||||
$page = (int) ($this->request->getGet('page') ?? 1);
|
$page = (int) ($this->request->getGet('page') ?? 1);
|
||||||
|
|
||||||
@@ -752,6 +877,10 @@ class UserController extends BaseController
|
|||||||
// Method to update an existing user
|
// Method to update an existing user
|
||||||
public function updateUser()
|
public function updateUser()
|
||||||
{
|
{
|
||||||
|
if ($resp = $this->requirePermission('edit_user')) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
if (strtolower($this->request->getMethod()) !== 'post') {
|
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||||
return redirect()->to(site_url('user/user_list'))->with('error', 'Invalid request.');
|
return redirect()->to(site_url('user/user_list'))->with('error', 'Invalid request.');
|
||||||
}
|
}
|
||||||
@@ -800,9 +929,6 @@ class UserController extends BaseController
|
|||||||
'status' => trim((string)$this->request->getPost('status')),
|
'status' => trim((string)$this->request->getPost('status')),
|
||||||
'is_suspended' => $toBool('is_suspended'),
|
'is_suspended' => $toBool('is_suspended'),
|
||||||
'is_verified' => $toBool('is_verified'),
|
'is_verified' => $toBool('is_verified'),
|
||||||
'token' => trim((string)$this->request->getPost('token')),
|
|
||||||
'updated_at' => $toDT('updated_at'),
|
|
||||||
'created_at' => $toDT('created_at'),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ class ConfigurationModel extends Model
|
|||||||
*/
|
*/
|
||||||
public function getConfigValueByKey(string $key)
|
public function getConfigValueByKey(string $key)
|
||||||
{
|
{
|
||||||
// Deterministic read in case historical duplicates exist
|
// Use a fresh builder to avoid stale state from shared model builder.
|
||||||
$result = $this->where('config_key', $key)
|
$builder = $this->db->table($this->table);
|
||||||
|
$result = $builder->where('config_key', $key)
|
||||||
->orderBy('id', 'DESC')
|
->orderBy('id', 'DESC')
|
||||||
->first();
|
->get(1)
|
||||||
return $result ? $result['config_value'] : null;
|
->getRowArray();
|
||||||
|
return $result['config_value'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class SubjectCurriculumModel extends Model
|
|||||||
return $this->where('class_id', $classId)
|
return $this->where('class_id', $classId)
|
||||||
->where('subject', $subject)
|
->where('subject', $subject)
|
||||||
->orderBy('unit_number', 'ASC')
|
->orderBy('unit_number', 'ASC')
|
||||||
|
->orderBy("CAST(SUBSTRING_INDEX(chapter_name, '.', 1) AS UNSIGNED)", 'ASC', false)
|
||||||
->orderBy('chapter_name', 'ASC')
|
->orderBy('chapter_name', 'ASC')
|
||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,8 +167,13 @@ class TimeService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sourceTz = $sourceTz ?: $this->serverTimezone;
|
|
||||||
$targetTz = $targetTz ?: $this->userTimezone();
|
$targetTz = $targetTz ?: $this->userTimezone();
|
||||||
|
if ($sourceTz === null && $this->isDateOnlyString($value)) {
|
||||||
|
// Date-only strings should not shift across timezones.
|
||||||
|
$sourceTz = $targetTz;
|
||||||
|
} else {
|
||||||
|
$sourceTz = $sourceTz ?: $this->serverTimezone;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($value instanceof Time) {
|
if ($value instanceof Time) {
|
||||||
@@ -204,4 +209,14 @@ class TimeService
|
|||||||
{
|
{
|
||||||
return (string) ($this->toUTC($value, $fromTz, $format) ?? '');
|
return (string) ($this->toUTC($value, $fromTz, $format) ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function isDateOnlyString($value): bool
|
||||||
|
{
|
||||||
|
if (!is_string($value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = trim($value);
|
||||||
|
return (bool) preg_match('/^\d{4}-\d{2}-\d{2}$/', $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,6 +250,54 @@
|
|||||||
$analysisSectionTotals[] = (int)($s['total_students'] ?? 0);
|
$analysisSectionTotals[] = (int)($s['total_students'] ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Student absences/late list ----
|
||||||
|
$sectionLabelByKey = [];
|
||||||
|
foreach ($grades as $classId => $sections) {
|
||||||
|
foreach ($sections as $section) {
|
||||||
|
$sectionKey = (string)($section['class_section_id'] ?? ($section['id'] ?? ''));
|
||||||
|
if ($sectionKey === '') continue;
|
||||||
|
$secNameRaw = trim((string)($section['class_section_name'] ?? ''));
|
||||||
|
$sectionLabelByKey[$sectionKey] = $secNameRaw !== '' ? $secNameRaw : ('Section ' . $sectionKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$studentIssueRows = [];
|
||||||
|
foreach ($studentsBySection as $sectionKey => $students) {
|
||||||
|
foreach ($students as $stu) {
|
||||||
|
$sid = (int)($stu['id'] ?? 0);
|
||||||
|
if ($sid <= 0) continue;
|
||||||
|
$entries = $attendanceData[$sectionKey][$sid] ?? [];
|
||||||
|
if (!is_array($entries)) continue;
|
||||||
|
$abs = 0;
|
||||||
|
$late = 0;
|
||||||
|
foreach ($entries as $e) {
|
||||||
|
$d = substr((string)($e['date'] ?? ''), 0, 10);
|
||||||
|
if ($d === '') continue;
|
||||||
|
if ($filterStart !== '' && $d < $filterStart) continue;
|
||||||
|
if ($filterEnd !== '' && $d > $filterEnd) continue;
|
||||||
|
$st = strtolower(trim((string)($e['status'] ?? '')));
|
||||||
|
if ($st === 'absent') {
|
||||||
|
$abs++;
|
||||||
|
} elseif ($st === 'late') {
|
||||||
|
$late++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (($abs + $late) <= 0) continue;
|
||||||
|
$studentIssueRows[] = [
|
||||||
|
'name' => trim((string)($stu['firstname'] ?? '') . ' ' . (string)($stu['lastname'] ?? '')),
|
||||||
|
'section' => $sectionLabelByKey[(string)$sectionKey] ?? ('Section ' . $sectionKey),
|
||||||
|
'absent' => $abs,
|
||||||
|
'late' => $late,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usort($studentIssueRows, static function ($a, $b) {
|
||||||
|
$sec = strcmp($a['section'], $b['section']);
|
||||||
|
if ($sec !== 0) return $sec;
|
||||||
|
return strcmp($a['name'], $b['name']);
|
||||||
|
});
|
||||||
|
|
||||||
$totalDaysForPercent = 0;
|
$totalDaysForPercent = 0;
|
||||||
if ($filterStart === '' && $filterEnd === '' && !empty($totalPassedDays)) {
|
if ($filterStart === '' && $filterEnd === '' && !empty($totalPassedDays)) {
|
||||||
$totalDaysForPercent = (int)$totalPassedDays;
|
$totalDaysForPercent = (int)$totalPassedDays;
|
||||||
@@ -373,6 +421,37 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="attn-analysis-card attn-analysis-wide">
|
||||||
|
<h6>Students With Absences / Late</h6>
|
||||||
|
<div class="attn-analysis-scroll">
|
||||||
|
<table id="studentIssueTable" class="attn-analysis-table no-mgmt-sticky" data-no-mgmt-sticky>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Student Name</th>
|
||||||
|
<th>Class Section</th>
|
||||||
|
<th class="text-end">Nbr of ABS</th>
|
||||||
|
<th class="text-end">Nbr of LATE</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($studentIssueRows)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center text-muted">No absences or late records in the selected range.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($studentIssueRows as $row): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= esc($row['name']) ?></td>
|
||||||
|
<td><?= esc($row['section']) ?></td>
|
||||||
|
<td class="text-end"><?= (int)$row['absent'] ?></td>
|
||||||
|
<td class="text-end"><?= (int)$row['late'] ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -480,6 +559,13 @@
|
|||||||
info: false,
|
info: false,
|
||||||
order: [[0, 'asc']]
|
order: [[0, 'asc']]
|
||||||
});
|
});
|
||||||
|
$('#studentIssueTable').DataTable({
|
||||||
|
paging: true,
|
||||||
|
searching: true,
|
||||||
|
info: true,
|
||||||
|
order: [[1, 'asc'], [0, 'asc']],
|
||||||
|
pageLength: 25
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -107,7 +107,10 @@
|
|||||||
<td><?= esc($flag['flag_state']) ?></td>
|
<td><?= esc($flag['flag_state']) ?></td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<form id="flagForm_<?= $flag['id'] ?>" method="post">
|
<form id="flagForm_<?= $flag['id'] ?>" method="post"
|
||||||
|
action="<?= site_url('flags/update_state/' . (int) $flag['id']) ?>"
|
||||||
|
data-action-close="<?= site_url('flags/closeFlag/' . (int) $flag['id']) ?>"
|
||||||
|
data-action-cancel="<?= site_url('flags/cancelFlag/' . (int) $flag['id']) ?>">
|
||||||
<?= csrf_field() ?>
|
<?= csrf_field() ?>
|
||||||
|
|
||||||
<select name="flag_state" class="form-select" id="flag_state_<?= $flag['id'] ?>"
|
<select name="flag_state" class="form-select" id="flag_state_<?= $flag['id'] ?>"
|
||||||
@@ -347,9 +350,9 @@
|
|||||||
|
|
||||||
// Set form action based on flag state
|
// Set form action based on flag state
|
||||||
if (flagState === "Closed") {
|
if (flagState === "Closed") {
|
||||||
form.action = `/flags/closeFlag/${currentFlagId}`;
|
form.action = form.dataset.actionClose || form.action;
|
||||||
} else if (flagState === "Canceled") {
|
} else if (flagState === "Canceled") {
|
||||||
form.action = `/flags/cancelFlag/${currentFlagId}`;
|
form.action = form.dataset.actionCancel || form.action;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Description set for form submission:", description); // For debugging
|
console.log("Description set for form submission:", description); // For debugging
|
||||||
@@ -357,6 +360,10 @@
|
|||||||
|
|
||||||
const modal = bootstrap.Modal.getInstance(document.getElementById('descriptionModal'));
|
const modal = bootstrap.Modal.getInstance(document.getElementById('descriptionModal'));
|
||||||
modal.hide();
|
modal.hide();
|
||||||
|
|
||||||
|
if (form && form.action) {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('flagStateDescription').addEventListener('input', function() {
|
document.getElementById('flagStateDescription').addEventListener('input', function() {
|
||||||
|
|||||||
@@ -11,9 +11,13 @@
|
|||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<?= esc(ucfirst($semester ?? '')) ?> • <?= esc($schoolYear ?? '') ?>
|
<?= esc(ucfirst($semester ?? '')) ?> • <?= esc($schoolYear ?? '') ?>
|
||||||
</div>
|
</div>
|
||||||
<a class="btn btn-outline-secondary btn-sm" href="<?= base_url('grading') ?>">
|
<?php if (!empty($canViewGrading)): ?>
|
||||||
Back to Grading
|
<a class="btn btn-outline-secondary btn-sm" href="<?= base_url('grading') ?>">
|
||||||
</a>
|
Back to Grading
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted small">You do not have access to the Grading page.</span>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
@@ -89,7 +93,7 @@
|
|||||||
<option value="Open" <?= ($row['status'] ?? 'Open') === 'Open' ? 'selected' : '' ?>>Open</option>
|
<option value="Open" <?= ($row['status'] ?? 'Open') === 'Open' ? 'selected' : '' ?>>Open</option>
|
||||||
<option value="Closed" <?= ($row['status'] ?? '') === 'Closed' ? 'selected' : '' ?>>Closed</option>
|
<option value="Closed" <?= ($row['status'] ?? '') === 'Closed' ? 'selected' : '' ?>>Closed</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" name="note" class="form-control form-control-sm" style="width: 140px;" placeholder="Note (optional)">
|
<input type="text" name="note" class="form-control form-control-sm" style="width: 140px;" placeholder="Note (optional)" value="<?= esc((string)($row['note'] ?? '')) ?>">
|
||||||
<button type="submit" class="btn btn-sm btn-outline-secondary">Update</button>
|
<button type="submit" class="btn btn-sm btn-outline-secondary">Update</button>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/** @var string $school_year */
|
/** @var string $school_year */
|
||||||
/** @var array<string> $schoolYears */
|
/** @var array<string> $schoolYears */
|
||||||
/** @var array<int,array{parent_id:int,parent_name:string,email:string,total_invoice:float,total_balance:float,total_discount:float,total_paid:float,remaining_installments:int,installment_amount:float,type:string,has_installment?:int,next_installment?:string}> $rows */
|
/** @var array<int,array{parent_id:int,parent_name:string,email:string,total_invoice:float,total_balance:float,total_discount:float,total_paid:float,payment_count:int,remaining_installments:int,installment_amount:float,type:string,has_installment?:int,next_installment?:string}> $rows */
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?= $this->extend('layout/management_layout') ?>
|
<?= $this->extend('layout/management_layout') ?>
|
||||||
@@ -15,8 +15,6 @@
|
|||||||
.table thead th { background: var(--mgmt-thead-bg, #f1f3f5); }
|
.table thead th { background: var(--mgmt-thead-bg, #f1f3f5); }
|
||||||
.actions { white-space: nowrap; }
|
.actions { white-space: nowrap; }
|
||||||
.actions .btn { --bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; }
|
.actions .btn { --bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; }
|
||||||
.email-cell { max-width: 280px; overflow: hidden; text-overflow: ellipsis; }
|
|
||||||
@media (max-width: 576px){ .email-cell { max-width: 180px; } }
|
|
||||||
/* Disable sticky header for this table to avoid overlap */
|
/* Disable sticky header for this table to avoid overlap */
|
||||||
table.no-mgmt-sticky thead th { position: static !important; }
|
table.no-mgmt-sticky thead th { position: static !important; }
|
||||||
</style>
|
</style>
|
||||||
@@ -54,7 +52,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Parent</th>
|
<th>Parent</th>
|
||||||
<th>Email</th>
|
<th class="text-center">Nbr of Installements</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th class="text-end">Invoice Amount</th>
|
<th class="text-end">Invoice Amount</th>
|
||||||
<th class="text-end">Applied Discount</th>
|
<th class="text-end">Applied Discount</th>
|
||||||
@@ -86,7 +84,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<small class="text-muted">#<?= (int)$r['parent_id'] ?></small>
|
<small class="text-muted">#<?= (int)$r['parent_id'] ?></small>
|
||||||
</td>
|
</td>
|
||||||
<td class="email-cell"><a href="mailto:<?= esc($r['email']) ?>"><?= esc($r['email']) ?></a></td>
|
<td class="text-center"><?= (int)($r['payment_count'] ?? 0) ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (($r['type'] ?? '') === 'no_payment'): ?>
|
<?php if (($r['type'] ?? '') === 'no_payment'): ?>
|
||||||
<span class="badge bg-danger badge-type">no payment</span>
|
<span class="badge bg-danger badge-type">no payment</span>
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<?= $this->extend('layout/register_layout') ?>
|
||||||
|
<?= $this->section('content') ?>
|
||||||
|
|
||||||
|
<div class="registration-form container mt-5 mb-5">
|
||||||
|
<form method="post" action="<?= base_url('set_authorized_user_password/' . $userId) ?>" onsubmit="return validatePassword()" autocomplete="off">
|
||||||
|
<?= csrf_field(); ?>
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<a href="<?= base_url('/') ?>">
|
||||||
|
<img src="<?= base_url('assets/images/alrahma_logo.png') ?>" alt="" style="width: 180px; height: 120px;">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="text-center text-success" style="font-family: Arial, sans-serif;">Create Your Password</h3>
|
||||||
|
<br>
|
||||||
|
<input type="hidden" name="user_id" value="<?= esc($userId); ?>" required>
|
||||||
|
<input type="hidden" name="token" value="<?= esc($token ?? ''); ?>" required>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="input-with-icon">
|
||||||
|
<input type="password"
|
||||||
|
class="form-control item"
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
placeholder="Enter new password"
|
||||||
|
maxlength="40"
|
||||||
|
required
|
||||||
|
autocomplete="new-password"
|
||||||
|
oncopy="return false"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false">
|
||||||
|
<span class="toggle-password" onclick="togglePassword('password', this)">
|
||||||
|
<i class="fa-solid fa-eye"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<small id="passwordHelp" class="text-danger d-none">
|
||||||
|
Password must be at least 8 characters long, contain a number, an uppercase letter, a lowercase letter, and one special character: @, -, =, +, *, #, $, %, &, !
|
||||||
|
</small>
|
||||||
|
<small id="passwordCopyWarning" class="text-muted d-none">
|
||||||
|
Copy and paste are disabled for security reasons.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="input-with-icon">
|
||||||
|
<input type="password"
|
||||||
|
class="form-control item"
|
||||||
|
id="password_confirm"
|
||||||
|
name="password_confirm"
|
||||||
|
placeholder="Confirm new password"
|
||||||
|
maxlength="40"
|
||||||
|
required
|
||||||
|
autocomplete="new-password"
|
||||||
|
oncopy="return false"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false">
|
||||||
|
<span class="toggle-password" onclick="togglePassword('password_confirm', this)">
|
||||||
|
<i class="fa-solid fa-eye"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<small id="confirmPasswordHelp" class="text-danger d-none">
|
||||||
|
Passwords do not match.
|
||||||
|
</small>
|
||||||
|
<small id="confirmCopyWarning" class="text-muted d-none">
|
||||||
|
Copy and paste are disabled for security reasons.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3 d-grid">
|
||||||
|
<button type="submit" class="btn btn-success item">Save Password</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?= $this->endSection() ?>
|
||||||
|
|
||||||
|
<?= $this->section('scripts') ?>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const showWarning = (inputId, warningId) => {
|
||||||
|
const input = document.getElementById(inputId);
|
||||||
|
const warning = document.getElementById(warningId);
|
||||||
|
|
||||||
|
['copy', 'paste', 'cut'].forEach(eventName => {
|
||||||
|
input.addEventListener(eventName, (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
warning.classList.remove('d-none');
|
||||||
|
|
||||||
|
if (warning.timeout) clearTimeout(warning.timeout);
|
||||||
|
warning.timeout = setTimeout(() => {
|
||||||
|
warning.classList.add('d-none');
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
showWarning('password', 'passwordCopyWarning');
|
||||||
|
showWarning('password_confirm', 'confirmCopyWarning');
|
||||||
|
});
|
||||||
|
|
||||||
|
function togglePassword(fieldId, iconContainer) {
|
||||||
|
const input = document.getElementById(fieldId);
|
||||||
|
const icon = iconContainer.querySelector('i');
|
||||||
|
|
||||||
|
if (input.type === 'password') {
|
||||||
|
input.type = 'text';
|
||||||
|
icon.classList.remove('fa-eye');
|
||||||
|
icon.classList.add('fa-eye-slash');
|
||||||
|
} else {
|
||||||
|
input.type = 'password';
|
||||||
|
icon.classList.remove('fa-eye-slash');
|
||||||
|
icon.classList.add('fa-eye');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePassword() {
|
||||||
|
const password = document.getElementById('password').value;
|
||||||
|
const passwordConfirm = document.getElementById('password_confirm').value;
|
||||||
|
const passwordHelp = document.getElementById('passwordHelp');
|
||||||
|
const confirmPasswordHelp = document.getElementById('confirmPasswordHelp');
|
||||||
|
|
||||||
|
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@\-=\+*#$%&!?])[A-Za-z\d@\-=\+*#$%&!?]{8,}$/;
|
||||||
|
|
||||||
|
let valid = true;
|
||||||
|
|
||||||
|
if (!passwordRegex.test(password)) {
|
||||||
|
passwordHelp.classList.remove('d-none');
|
||||||
|
valid = false;
|
||||||
|
} else {
|
||||||
|
passwordHelp.classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password !== passwordConfirm) {
|
||||||
|
confirmPasswordHelp.classList.remove('d-none');
|
||||||
|
valid = false;
|
||||||
|
} else {
|
||||||
|
confirmPasswordHelp.classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<?= $this->endSection() ?>
|
||||||
+253
-258
@@ -1,259 +1,254 @@
|
|||||||
Grade,Unit,Unit Title,chapter
|
Grade,Unit,Unit Title,chapter
|
||||||
1,1,Aqaid: Our Belief,Allahﷻ: Our Creator
|
1,1,Aqaid: Our Belief,1. Allah: Our Creator
|
||||||
1,1,Aqaid: Our Belief,Islam
|
1,1,Aqaid: Our Belief,2. Islam
|
||||||
1,1,Aqaid: Our Belief,Our Faith
|
1,1,Aqaid: Our Belief,3. Our Faith
|
||||||
1,1,Aqaid: Our Belief,Nabi Muhammadﷺ
|
1,1,Aqaid: Our Belief,4. Nabi Muhammad (s)
|
||||||
1,1,Aqaid: Our Belief,The Qur’an
|
1,1,Aqaid: Our Belief,5. The Qur’an
|
||||||
1,2,Knowing Allahﷻ,Allahﷻ Loves Us
|
1,2,Knowing Allah,6. Allah Loves Us
|
||||||
1,2,Knowing Allahﷻ,Remembering Allahﷻ
|
1,2,Knowing Allah,7. Remembering Allah
|
||||||
1,2,Knowing Allahﷻ,Allahﷻ Rewards Us
|
1,2,Knowing Allah,8. Allah Rewards Us
|
||||||
1,3,Our Ibadat,Five Pillars of Islam
|
1,3,Our Ibadat,9. Five Pillars of Islam
|
||||||
1,3,Our Ibadat,Shahadah: The First Pillar
|
1,3,Our Ibadat,10. Shahadah: The First Pillar
|
||||||
1,3,Our Ibadat,Salah: The Second Pillar
|
1,3,Our Ibadat,11. Salat: The Second Pillar
|
||||||
1,3,Our Ibadat,Zakat: The Third Pillar
|
1,3,Our Ibadat,12. Zakat: The Third Pillar
|
||||||
1,3,Our Ibadat,Fasting: The Fourth Pillar
|
1,3,Our Ibadat,13. Fasting: The Fourth Pillar
|
||||||
1,3,Our Ibadat,Hajj: The Fifth Pillar
|
1,3,Our Ibadat,14. Hajj: The Fifth Pillar
|
||||||
1,4,Messengers of Allah,Adam (A): The First Nabi
|
1,4,Messengers of Allah,15. Adam (A): The First Nabi
|
||||||
1,4,Messengers of Allah,Nuh (A): Saved From Flood
|
1,4,Messengers of Allah,16. Nuh (A): Saved From the Great Flood
|
||||||
1,4,Messengers of Allah,Ibrahim (A): Never Listen to Shaitan
|
1,4,Messengers of Allah,17. Ibrahim (A): Never Listen to Shaitan
|
||||||
1,4,Messengers of Allah,Musa (A): Challenging A Bad Ruler
|
1,4,Messengers of Allah,18. Musa (A): Challenging a Bad Ruler
|
||||||
1,4,Messengers of Allah,Isa (A): A Great Nabi of Allahﷻ
|
1,4,Messengers of Allah,19. Isa (A): A Great Nabi of Allah
|
||||||
1,5,Other Basics of Islam,Angels: They Always Work for Allahﷻ
|
1,5,Other Basics of Islam,20. Angels: They Always Work for Allah
|
||||||
1,5,Other Basics of Islam,Shaitan: Our Enemy
|
1,5,Other Basics of Islam,21. Shaitan: Our Enemy
|
||||||
1,5,Other Basics of Islam,Makkah and Madinah
|
1,5,Other Basics of Islam,22. Makkah and Madinah
|
||||||
1,5,Other Basics of Islam,Eid: Two Festivals
|
1,5,Other Basics of Islam,23. Eid: Two Festivals
|
||||||
1,6,Akhlaq and Adab in Islam,Good Manners
|
1,6,Akhlaq and Adab in Islam,24. Good Manners
|
||||||
1,6,Akhlaq and Adab in Islam,Kindness and Sharing
|
1,6,Akhlaq and Adab in Islam,25. Kindness and Sharing
|
||||||
1,6,Akhlaq and Adab in Islam,Respect
|
1,6,Akhlaq and Adab in Islam,26. Respect
|
||||||
1,6,Akhlaq and Adab in Islam,Forgiveness
|
1,6,Akhlaq and Adab in Islam,27. Forgiveness
|
||||||
1,6,Akhlaq and Adab in Islam,Thanking Allahﷻ
|
1,6,Akhlaq and Adab in Islam,28. Thanking Allah
|
||||||
2,1,The Creator—His Message,Allahﷻ: Our Creator
|
2,1,The Creator and His Message,1. Allah: Our Creator
|
||||||
2,1,The Creator—His Message,How Does Allahﷻ Create?
|
2,1,The Creator and His Message,2. How Does Allah Create?
|
||||||
2,1,The Creator—His Message,Allahﷻ: What Does He Do?
|
2,1,The Creator and His Message,3. What Does Allah Do?
|
||||||
2,1,The Creator—His Message,What Does Allahﷻ Not Do
|
2,1,The Creator and His Message,4, Allah: What Does He Not Do
|
||||||
2,1,The Creator—His Message,The Qur’an
|
2,1,The Creator and His Message,5. The Qur’an
|
||||||
2,1,The Creator—His Message,Hadith and Sunnah
|
2,1,The Creator and His Message,6. Hadith and Sunnah
|
||||||
2,2,Our Ibadat,Shahadah: The First Pillar
|
2,2,Our Ibadat,7. Shahadah: The First Pillar
|
||||||
2,2,Our Ibadat,Salah: The Second Pillar
|
2,2,Our Ibadat,8. Salat: The Second Pillar
|
||||||
2,2,Our Ibadat,Zakah: The Third Pillar
|
2,2,Our Ibadat,9. Zakah: The Third Pillar
|
||||||
2,2,Our Ibadat,Sawm: The Fourth Pillar
|
2,2,Our Ibadat,10. Sawm: The Fourth Pillar
|
||||||
2,2,Our Ibadat,Hajj: The Fifth Pillar
|
2,2,Our Ibadat,11. Hajj: The Fifth Pillar
|
||||||
2,2,Our Ibadat,Wudu: Keeping Our Bodies Clean
|
2,2,Our Ibadat,12. Wudu: Cleaning Before Salat
|
||||||
2,3,Messengers of Allah,Ibrahim (A): A Friend of Allah
|
2,3,The Messengers of Allah,13. Ibrahim (A): A Friend of Allah
|
||||||
2,3,Messengers of Allah,Yaqub (A) and Yusuf (A)
|
2,3,The Messengers of Allah,14. Yaqub (A) and Yusuf (A)
|
||||||
2,3,Messengers of Allah,Musa (A) and Harun (A)
|
2,3,The Messengers of Allah,15. Musa (A) and Harun (A)
|
||||||
2,3,Messengers of Allah,Yunus (A)
|
2,3,The Messengers of Allah,16. Yunus (A)
|
||||||
2,3,Messengers of Allah,Nabi Muhammadﷺ
|
2,3,The Messengers of Allah,17. Nabi Muhammad ﷺ
|
||||||
2,4,Learning About Islam,Obey Allahﷻ Obey Rasulﷺ
|
2,4,Learning About Islam,18. Obey Allah, Obey Rasul ﷺ
|
||||||
2,4,Learning About Islam,Day of Judgment
|
2,4,Learning About Islam,19. Day of Judgment
|
||||||
2,4,Learning About Islam,Our Masjid
|
2,4,Learning About Islam,20. Our Masjid
|
||||||
2,4,Learning About Islam,Islamic Phrases
|
2,4,Learning About Islam,21. Islamic Phrases
|
||||||
2,4,Learning About Islam,Food that We May Eat
|
2,4,Learning About Islam,22. Food that We May Eat
|
||||||
2,5,Akhlaq and Adab in Islam,Truthfulness
|
2,5,Akhlaq and Adab in Islam,23. Truthfulness
|
||||||
2,5,Akhlaq and Adab in Islam,Kindness
|
2,5,Akhlaq and Adab in Islam,24. Kindness
|
||||||
2,5,Akhlaq and Adab in Islam,Respect
|
2,5,Akhlaq and Adab in Islam,25. Respect
|
||||||
2,5,Akhlaq and Adab in Islam,Responsibility
|
2,5,Akhlaq and Adab in Islam,26. Responsibility
|
||||||
2,5,Akhlaq and Adab in Islam,Obedience
|
2,5,Akhlaq and Adab in Islam,27. Obedience
|
||||||
2,5,Akhlaq and Adab in Islam,Cleanliness
|
2,5,Akhlaq and Adab in Islam,28. Cleanliness
|
||||||
2,5,Akhlaq and Adab in Islam,Honesty
|
2,5,Akhlaq and Adab in Islam,29. Honesty
|
||||||
3,1,Knowing About Allah,What Does Allahﷻ Do?
|
3,1,Knowing About Allāh ﷺ,1. Who Is Allāh ﷺ?
|
||||||
3,1,Knowing About Allah,What Allahﷻ Is and Is Not
|
3,1,Knowing About Allāh ﷺ,2. What Allāh ﷺ Is and Is Not
|
||||||
3,1,Knowing About Allah,Allahﷻ: The Most-Merciful
|
3,1,Knowing About Allāh ﷺ,3. Allāh ﷺ: The Most-Merciful, Most-Rewarding
|
||||||
3,1,Knowing About Allah,Allahﷻ: The Best Judge
|
3,1,Knowing About Allāh ﷺ,4. Allāh ﷺ: The Best Judge
|
||||||
3,2,What Islam Says,We Are Muslims: We Have ‘Iman
|
3,1,Knowing About Allāh ﷺ,5. What Does Allāh ﷺ Want Us to Do?
|
||||||
3,2,What Islam Says,What Does Allahﷻ Want Us to Do?
|
3,2,Teachings of Islam,6. We Are Muslims: We Have ‘Īmān
|
||||||
3,2,What Islam Says,Hadith
|
3,2,Teachings of Islam,7. Belief in the Qur’ān
|
||||||
3,2,What Islam Says,Jinn
|
3,2,Teachings of Islam,8. Belief in the Messengers
|
||||||
3,2,What Islam Says,Muslims in North America
|
3,2,Teachings of Islam,9. Hadīth and Sunnah
|
||||||
3,2,What Islam Says,The Right Path: The Straight Path
|
3,2,Teachings of Islam,10. Jinn
|
||||||
3,3,Why Do We Worship,Shahadah: Allahﷻ is One
|
3,2,Teachings of Islam,11. Muslims in North America
|
||||||
3,3,Why Do We Worship,Types of Salat
|
3,2,Teachings of Islam,12. The Straight Path: The Right Path
|
||||||
3,3,Why Do We Worship,Why We Make Salat
|
3,3,Nabi Muhammad ﷺ,13. Kindness of Rasūlullāh ﷺ
|
||||||
3,3,Why Do We Worship,Why Do We pay Zakat?
|
3,3,Nabi Muhammad ﷺ,14. How Rasūlullāh ﷺ Treated Others
|
||||||
3,3,Why Do We Worship,Why Do We Fast?
|
3,3,Nabi Muhammad ﷺ,15. Our Relationship With Rasūlullāh ﷺ
|
||||||
3,3,Why Do We Worship,Why Do We Go for Hajj?
|
3,4,Messengers of Allāh ﷺ,16. Ismā‘īl (A) and Ishāq (A): Nabi of Allāh ﷺ
|
||||||
3,4,Life of Nabi Muhammadﷺ,The Nabiﷺ in Makkah
|
3,4,Messengers of Allāh ﷺ,17. Shu‘aib (A): A Nabi of Allāh ﷺ
|
||||||
3,4,Life of Nabi Muhammadﷺ,The Nabiﷺ in Madinah
|
3,4,Messengers of Allāh ﷺ,18. Dāwūd (A): A Nabi of Allāh ﷺ
|
||||||
3,4,Life of Nabi Muhammadﷺ,How Rasulullahﷺ Treated Others
|
3,4,Messengers of Allāh ﷺ,19. ‘Īsā (A): A Nabi of Allāh ﷺ
|
||||||
3,5,Messengers of Allah,Isma‘il (A) and Ishaq (A)
|
3,5,Learning About Islam,20. The Ka‘bah
|
||||||
3,5,Messengers of Allah,Dawud (A): A Nabi of Allahﷻ
|
3,5,Learning About Islam,21. Masjid an-Nabawī: The Nabi’s Masjid
|
||||||
3,5,Messengers of Allah,‘Isa (A): A Nabi of Allahﷻ
|
3,5,Learning About Islam,22. Bilāl ibn Rabāh
|
||||||
3,6,Akhlaq and Adab in Islam,Being Kind: A Virtue of the Believers
|
3,5,Learning About Islam,23. Zaid ibn Hārithah
|
||||||
3,6,Akhlaq and Adab in Islam,Forgiveness: A Good Quality
|
3,6,Akhlaq and Adab in Islam,24. Ways To Be a Good Person
|
||||||
3,6,Akhlaq and Adab in Islam,Good Deeds: A Duty of the Believers
|
3,6,Akhlaq and Adab in Islam,25. Kindness: A Virtue of the Believers
|
||||||
3,6,Akhlaq and Adab in Islam,Cleanliness: A Quality of Believers
|
3,6,Akhlaq and Adab in Islam,26. Forgiveness: A Quality of the Believers
|
||||||
3,6,Akhlaq and Adab in Islam,A Muslim Family
|
3,6,Akhlaq and Adab in Islam,27. Good Deeds: A Duty of the Believers
|
||||||
3,6,Akhlaq and Adab in Islam,Perseverance: Never Give Up
|
3,6,Akhlaq and Adab in Islam,28. Perseverance: Never Give Up
|
||||||
3,6,Akhlaq and Adab in Islam,Punctuality: Doing Things on Time
|
3,6,Akhlaq and Adab in Islam,29. Punctuality: Doing Things on Time
|
||||||
4,1,Knowing the Creator,Rewards of Allahﷻ: Everybody Receives Them
|
4,1,Knowing the Creator,1. Rewards of Allah: Everybody Receives Them
|
||||||
4,1,Knowing the Creator,Discipline of Allahﷻ
|
4,1,Knowing the Creator,1. Discipline of Allah: Because He Loves Us
|
||||||
4,1,Knowing the Creator,Names of Allahﷻ
|
4,1,Knowing the Creator,3. Names of Allah
|
||||||
4,1,Knowing the Creator,Books of Allahﷻ
|
4,1,Knowing the Creator,4. Books of Allah
|
||||||
4,2,How Islam Changed Arabia,Pre-Islamic Arabia
|
4,2,How Islam Changed Arabia,5. Pre-Islamic Arabia: Age of Ignorance
|
||||||
4,2,How Islam Changed Arabia,The Year of the Elephant
|
4,2,How Islam Changed Arabia,6. The Year of the Elephant
|
||||||
4,2,How Islam Changed Arabia,Early Life of Muhammadﷺ
|
4,2,How Islam Changed Arabia,7. Early Life of Muhammad ﷺ
|
||||||
4,2,How Islam Changed Arabia,Life Before Becoming a Nabi
|
4,2,How Islam Changed Arabia,8. Life Before Becoming a Nabi
|
||||||
4,2,How Islam Changed Arabia,First Revelation
|
4,2,How Islam Changed Arabia,9. First Revelation
|
||||||
4,2,How Islam Changed Arabia,Makkah Period
|
4,2,How Islam Changed Arabia,10. Makkah Period: The Early Years of the Muslims
|
||||||
4,2,How Islam Changed Arabia,Hijrat to Madinah
|
4,2,How Islam Changed Arabia,11. Hijrat to Madinah: The Migration that Shaped History
|
||||||
4,2,How Islam Changed Arabia,Madinah Period
|
4,2,How Islam Changed Arabia,12. Madinah Period: Islam Prospers
|
||||||
4,3,The Rightly Guided Khalifah,Abu Bakr: The First Khalifah
|
4,3,The Rightly Guided Khalifah,13. Abū Bakr (R): The First Khalifah
|
||||||
4,3,The Rightly Guided Khalifah,‘Umar ibn al-Khattab
|
4,3,The Rightly Guided Khalifah,14. ‘Umar al-Khaṭṭāb (R): The Second Khalifah
|
||||||
4,3,The Rightly Guided Khalifah,‘Uthman ibn ‘Affan
|
4,3,The Rightly Guided Khalifah,15. ‘Uthman Ibn ‘Affān (R): The Third Khalifah
|
||||||
4,3,The Rightly Guided Khalifah,‘Ali ibn Abu Talib
|
4,3,The Rightly Guided Khalifah,16. ‘Ali Ibn Abu Ṭālib (R): The Fourth Khalifah
|
||||||
4,4,The Messengers of Allah,Hud (A): Struggle to Guide People
|
4,4,Messengers of Allah,17. Hūd (A): Struggle to Guide Mankind
|
||||||
4,4,The Messengers of Allah,Salih (A): To Guide the Misguided
|
4,4,Messengers of Allah,18. Ṣāliḥ (A): Struggle to Guide the Misguided
|
||||||
4,4,The Messengers of Allah,Musa (A): His Life and Actions
|
4,4,Messengers of Allah,19. Mūsā (A): His Life and Achievements
|
||||||
4,4,The Messengers of Allah,Sulaiman (A): A Humble King
|
4,4,Messengers of Allah,20. Sulaimān (A): A King and a Servant of Allah ﷺ
|
||||||
4,5,Fiqh of Salat,Preparation for Salat
|
4,5,Fiqh of Salat,21. Preparation for Salat
|
||||||
4,5,Fiqh of Salat,Requirements of Salat
|
4,5,Fiqh of Salat,22. The Requirements of Salat
|
||||||
4,5,Fiqh of Salat,Mubtilat us-Salat
|
4,5,Fiqh of Salat,23. Mubṭilāt-us-Salāt: Things that Invalidate Salāt
|
||||||
4,5,Fiqh of Salat,How to Pray Behind an Imam
|
4,5,Fiqh of Salat,24. How to Pray Behind an Imām
|
||||||
4,6,General Islamic Topics,Compilers of Hadith
|
4,6,General Islamic Topics,25. Compilers of Hadīth
|
||||||
4,6,General Islamic Topics,Shaitan’s Mode of Operation
|
4,6,General Islamic Topics,26. Shaitan’s Mode of Operation
|
||||||
4,6,General Islamic Topics,Day of Judgment
|
4,6,General Islamic Topics,27. Day of Judgment: The Day of Ultimate Justice
|
||||||
4,6,General Islamic Topics,Eid: Its Significance
|
4,6,General Islamic Topics,28. ‘Eid: Significance of the Festivities
|
||||||
4,6,General Islamic Topics,Truthfulness: A Quality of Muslim
|
4,6,General Islamic Topics,29. Truthfulness: An Important Quality for Muslims
|
||||||
4,6,General Islamic Topics,Perseverance: Keep on Trying
|
4,6,General Islamic Topics,30. Perseverance: Keep on Trying
|
||||||
5,1,"The Creator, His Message","Tawhid, Kafir, Kufr, Shirk, Nifaq"
|
5,1,The Creator,1. His Message, and His Messengers,Tawhid, Kafir, Kufr, Shirk, Nifaq
|
||||||
5,1,"The Creator, His Message",Why Should We Worship Allahﷻ?
|
5,1,The Creator,2. His Message, and His Messengers,Why Should We Worship Allah?
|
||||||
5,1,"The Creator, His Message",Revelation of the Qur’an
|
5,1,The Creator,3. His Message, and His Messengers,The Revelation of the Qur’an
|
||||||
5,1,"The Creator, His Message",Characteristics of the Messengers
|
5,1,The Creator,4. His Message, and His Messengers,Characteristics of the Messengers
|
||||||
5,2,"The Battles, Developments",Pledges of ‘Aqabah
|
5,2,The Battles and Other Developments,5. Pledges of ‘Aqabah: Invitation to Migrate
|
||||||
5,2,"The Battles, Developments",The Battle of Badr
|
5,2,The Battles and Other Developments,6. The Battle of Badr: Allah Supports the Righteous
|
||||||
5,2,"The Battles, Developments",The Battle of Uhud
|
5,2,The Battles and Other Developments,7. The Battle of Uhud: Obey Allah and Obey the Rasul ﷺ
|
||||||
5,2,"The Battles, Developments",The Battle of the Trench
|
5,2,The Battles and Other Developments,8. The Battle of the Trench: A Bloodless Battle
|
||||||
5,2,"The Battles, Developments",The Treaty of Hudaibiyah
|
5,2,The Battles and Other Developments,9. The Treaty of Hudaibiyah: A Clear Victory
|
||||||
5,2,"The Battles, Developments",Liberation of Makkah
|
5,2,The Battles and Other Developments,10. Liberation of Makkah: A Bloodless Victory
|
||||||
5,3,The Messengers of Allah,Adam (A): The Creation of Mankind
|
5,3,Stories of the Messengers of Allah,11. Adam (A): The Creation of Human Beings
|
||||||
5,3,The Messengers of Allah,Ibrahim (A) Debate with Polytheists
|
5,3,Stories of the Messengers of Allah,12. Ibrahim (A): His Debate with the Polytheists
|
||||||
5,3,The Messengers of Allah,Ibrahim (A): Plan Against Idols
|
5,3,Stories of the Messengers of Allah,13. Ibrahim (A): His Plan Against the Idols
|
||||||
5,3,The Messengers of Allah,Luqman (A): A Wise Man’s Lifelong Teachings
|
5,3,Stories of the Messengers of Allah,14. Luqmān (A): A Wise Man’s Lifelong Advice
|
||||||
5,3,The Messengers of Allah,Yusuf (A): His Childhood
|
5,3,Stories of the Messengers of Allah,15. Yūsuf (A): His Childhood and Life in Aziz’s Home
|
||||||
5,3,The Messengers of Allah,Yusuf (A): His Righteousness
|
5,3,Stories of the Messengers of Allah,16. Yūsuf (A): Standing Up for Righteousness
|
||||||
5,3,The Messengers of Allah,Yusuf (A): Dream Comes True
|
5,3,Stories of the Messengers of Allah,17. Yūsuf (A): A Childhood Dream Comes True
|
||||||
5,3,The Messengers of Allah,"Ayyub (A): Patience, Perseverance"
|
5,4,Islam in The World,20. Major Masājid in the World
|
||||||
5,3,The Messengers of Allah,"Zakariyyah (A), Yahya (A)"
|
5,5,Islamic Values and Teachings,21. Upholding Truth: A Duty of All Believers
|
||||||
5,4,Islam in the World,Major Masajid in the World
|
5,5,Islamic Values and Teachings,22. Responsibility and Punctuality
|
||||||
5,5,"Islamic Values, Teachings",Upholding Truth: A Duty for All Believers
|
5,5,Islamic Values and Teachings,23. My Mind, My Body: The Body is a Mirror of the Mind
|
||||||
5,5,"Islamic Values, Teachings",Responsibility and Punctuality
|
5,5,Islamic Values and Teachings,24. Kindness and Forgiveness
|
||||||
5,5,"Islamic Values, Teachings",My Mind My Body
|
5,5,Islamic Values and Teachings,25. The Middle Path: Ways to Avoid the Two Extremes
|
||||||
5,5,"Islamic Values, Teachings",Kindness and Forgiveness
|
5,5,Islamic Values and Teachings,26. Salat: Its Significance
|
||||||
5,5,"Islamic Values, Teachings",The Middle Path: Ways to Avoid Two Extremes
|
5,5,Islamic Values and Teachings,27. Sawm: Its Significance
|
||||||
5,5,"Islamic Values, Teachings",Salat: Its Significance
|
5,5,Islamic Values and Teachings,28. Zakat and Sadaqah: Similarities and Differences
|
||||||
5,5,"Islamic Values, Teachings",Sawm: Its Significance
|
6,1,The Creator,1. His Message, and His Messengers,Tawhid, Kafir, Kufr, Shirk, Nifaq
|
||||||
5,5,"Islamic Values, Teachings",Zakat and Sadaqah: Similarities and Differences
|
6,1,The Creator,2. His Message, and His Messengers,Why Should We Worship Allah?
|
||||||
6,1,The Creator—His Message,Attributes of Allahﷻ
|
6,1,The Creator,3. His Message, and His Messengers,The Revelation of the Qur’an
|
||||||
6,1,The Creator—His Message,The Promise of Allahﷻ
|
6,1,The Creator,4. His Message, and His Messengers,Characteristics of the Messengers
|
||||||
6,2,The Qur’an and Hadith,Objectives of the Qur’an?
|
6,2,The Battles and Other Developments,5. Pledges of ‘Aqabah: Invitation to Migrate
|
||||||
6,2,The Qur’an and Hadith,Compilation of the Qur’an
|
6,2,The Battles and Other Developments,6. The Battle of Badr: Allah Supports the Righteous
|
||||||
6,2,The Qur’an and Hadith,Previous Scriptures and the Qur’an
|
6,2,The Battles and Other Developments,7. The Battle of Uhud: Obey Allah and Obey the Rasul ﷺ
|
||||||
6,2,The Qur’an and Hadith,Compilation of Hadith
|
6,2,The Battles and Other Developments,8. The Battle of the Trench: A Bloodless Battle
|
||||||
6,3,Fundamentals of Deen,Importance of Shahadah
|
6,2,The Battles and Other Developments,9. The Treaty of Hudaibiyah: A Clear Victory
|
||||||
6,3,Fundamentals of Deen,Khushu in Salat
|
6,2,The Battles and Other Developments,10. Liberation of Makkah: A Bloodless Victory
|
||||||
6,3,Fundamentals of Deen,Taqwa: A Quality of Believers
|
6,3,Stories of the Messengers of Allah,11. Adam (A): The Creation of Human Beings
|
||||||
6,4,Messengers of Allah,Nuh (A)
|
6,3,Stories of the Messengers of Allah,12. Ibrahim (A): His Debate with the Polytheists
|
||||||
6,4,Messengers of Allah,"Talut, Jalut, and Dawud (A)"
|
6,3,Stories of the Messengers of Allah,13. Ibrahim (A): His Plan Against the Idols
|
||||||
6,4,Messengers of Allah,Dawud (A) and Sulaiman (A)
|
6,3,Stories of the Messengers of Allah,14. Luqmān (A): A Wise Man’s Lifelong Advice
|
||||||
6,4,Messengers of Allah,Musa (A) and Fir‘awn
|
6,3,Stories of the Messengers of Allah,15. Yūsuf (A): His Childhood and Life in Aziz’s Home
|
||||||
6,4,Messengers of Allah,Musa (A) and Khidir
|
6,3,Stories of the Messengers of Allah,16. Yūsuf (A): Standing Up for Righteousness
|
||||||
6,4,Messengers of Allah,‘Isa (A) and Maryam (ra)
|
6,3,Stories of the Messengers of Allah,17. Yūsuf (A): A Childhood Dream Comes True
|
||||||
6,5,Some Prominent Muslimah,Khadijah (ra)
|
6,4,Islam in The World,20. Major Masājid in the World
|
||||||
6,5,Some Prominent Muslimah,‘Aishah (ra)
|
6,5,Islamic Values and Teachings,21. Upholding Truth: A Duty of All Believers
|
||||||
6,5,Some Prominent Muslimah,Fatimah (ra)
|
6,5,Islamic Values and Teachings,22. Responsibility and Punctuality
|
||||||
6,5,Some Prominent Muslimah,Some Prominent Muslimahs
|
6,5,Islamic Values and Teachings,23. My Mind, My Body: The Body is a Mirror of the Mind
|
||||||
6,6,Knowledge Enrichment,Al-Qiyamah: The Awakening
|
6,5,Islamic Values and Teachings,24. Kindness and Forgiveness
|
||||||
6,6,Knowledge Enrichment,Ruh and Nafs: An Overview
|
6,5,Islamic Values and Teachings,25. The Middle Path: Ways to Avoid the Two Extremes
|
||||||
6,6,Knowledge Enrichment,Angels and Jinn: An Overview
|
6,5,Islamic Values and Teachings,26. Salat: Its Significance
|
||||||
6,6,Knowledge Enrichment,Shaitan: The Invisible Enemy
|
6,5,Islamic Values and Teachings,27. Sawm: Its Significance
|
||||||
6,7,The Current Society,My Friend Is Muslim Now
|
6,5,Islamic Values and Teachings,28. Zakat and Sadaqah: Similarities and Differences
|
||||||
6,7,The Current Society,Friendship
|
7,1,The Creator,1. Why Islam? What is Islam?
|
||||||
6,7,The Current Society,Muslims Around the World
|
7,1,The Creator,2. Belief in Allah
|
||||||
6,7,The Current Society,People of Other Faith
|
7,1,The Creator,3. The Qur’an: Its Qualitative Names
|
||||||
6,8,Developing Islamic Values,Greed and Dishonesty
|
7,1,The Creator,4. Istighfār: Seeking Forgiveness and Protection
|
||||||
6,8,Developing Islamic Values,Avoiding Extravagance
|
7,1,The Creator,5. Allah: Angry or Kind?
|
||||||
7,1,The Creator,Why Islam? what is Islam?
|
7,2,Stories of the Messengers,6. Ādam (A): The Trial of the First Messenger
|
||||||
7,1,The Creator,Belief in Allahﷻ
|
7,2,Stories of the Messengers,7. The Life of Ibrāhīm (A): Beginning a Nation
|
||||||
7,1,The Creator,The Qur’an: Its Qualitative Names
|
7,2,Stories of the Messengers,8. The Sacrifice of Ibrāhīm (A)
|
||||||
7,1,The Creator,Istighfar: Seeking Forgiveness of Allahﷻ
|
7,2,Stories of the Messengers,9. Lūt (A): A Message for Modern Societies
|
||||||
7,1,The Creator,Allahﷻ: Angry or Kind
|
7,2,Stories of the Messengers,10. Yūsuf (A): The Will to Overcome Temptation
|
||||||
7,2,Stories of the Messengers,Adam (A): Trial of the Messenger
|
7,3,Stories from the Qur’an,11. The Companions of the Cave
|
||||||
7,2,Stories of the Messengers,Life of Ibrahim (A)
|
7,3,Stories from the Qur’an,12. Dhu al-Qarnain: The Journey of a King
|
||||||
7,2,Stories of the Messengers,Sacrifice of Ibrahim (A)
|
7,3,Stories from the Qur’an,13. Effective Debate and Negotiation Styles in the Qur’an
|
||||||
7,2,Stories of the Messengers,Lut (A): Message for Modern Societies
|
7,4,Two Companions Who Shaped Islam,14. Abū Sufyān: His Life and Achievements
|
||||||
7,2,Stories of the Messengers,Yusuf (A)—The Will to Overcome Temptation
|
7,4,Two Companions Who Shaped Islam,15. Khālid Ibn al-Walīd: The “Sword of Allah”
|
||||||
7,3,Stories from the Qur’an,The Companions of the Cave
|
7,5,Knowledge Enrichment,16. Character of the Messengers
|
||||||
7,3,Stories from the Qur’an,Dhul Qurnain: Journey of a King
|
7,5,Knowledge Enrichment,17. Rasūlullāh’s Marriages
|
||||||
7,3,Stories from the Qur’an,Effective Debate and Negotiation Styles in the Qur’an
|
7,5,Knowledge Enrichment,18. Lailatul Qadr: The Night of Majesty
|
||||||
7,4,Two Companions,Abu Sufyan
|
7,5,Knowledge Enrichment,19. Fasting During Ramadan: The Month of Benefits
|
||||||
7,4,Two Companions,Khalid Ibn Walid (R)
|
7,5,Knowledge Enrichment,20. My Family is Muslim Now
|
||||||
7,5,Knowledge Enrichment,The character of the Messengers
|
7,5,Knowledge Enrichment,21. Science in the Qur’an
|
||||||
7,5,Knowledge Enrichment,Rasulullahﷺ Marriages
|
7,5,Knowledge Enrichment,22. Lessons From Past Civilizations
|
||||||
7,5,Knowledge Enrichment,Lailatul Qadr
|
7,6,Akhlaq and Adab in Islam,23. Amr Bil Ma’rūf: Enjoin Good Deeds
|
||||||
7,5,Knowledge Enrichment,Fasting During Ramadan
|
7,6,Akhlaq and Adab in Islam,24. Guard Your Tongue: Think Before You Speak
|
||||||
7,5,Knowledge Enrichment,My Family is Muslim Now
|
7,6,Akhlaq and Adab in Islam,25. Islamic Greeting: Wishing Peace
|
||||||
7,5,Knowledge Enrichment,Science in the Qur’an
|
7,6,Akhlaq and Adab in Islam,26. How to Achieve Success
|
||||||
7,5,Knowledge Enrichment,Lessons from Past Civilizations
|
7,6,Akhlaq and Adab in Islam,27. Permitted and Prohibited
|
||||||
7,6,Teachings of the Qur’an,Amr Bil Ma‘ruf
|
7,6,Akhlaq and Adab in Islam,28. Types of Behavior Allah Loves
|
||||||
7,6,Teachings of the Qur’an,Guard Your Tongue
|
8,1,Knowing the Creator,1. Divine Names
|
||||||
7,6,Teachings of the Qur’an,Islamic Greetings
|
8,1,Knowing the Creator,2. Sunan of Allah
|
||||||
7,6,Teachings of the Qur’an,How to Achieve Success
|
8,1,Knowing the Creator,3. Objectives of the Qur’an
|
||||||
7,6,Teachings of the Qur’an,Permitted and Prohibited
|
8,1,Knowing the Creator,4. Lessons from Sūrah al-Hujurāt
|
||||||
7,6,Teachings of the Qur’an,Types of Behavior Allahﷻ Loves
|
8,1,Knowing the Creator,5. True Piety: A Synthesis of Belief, Practice, and Conduct
|
||||||
8,1,Knowing the Creator,Divine Names
|
8,1,Knowing the Creator,6. Āyatul Kursi: The Throne Verse
|
||||||
8,1,Knowing the Creator,Sunan of Allahﷻ
|
8,2,Knowing the Messenger ﷺ,7. The Person Muhammad ﷺ
|
||||||
8,1,Knowing the Creator,Objectives of the Qur’an
|
8,2,Knowing the Messenger ﷺ,8. Farewell Pilgrimage
|
||||||
8,1,Knowing the Creator,Surah Hujurat: Its Teachings
|
8,2,Knowing the Messenger ﷺ,9. Finality of Prophethood
|
||||||
8,1,Knowing the Creator,True Piety: Analysis of Verse 2:177
|
8,2,Knowing the Messenger ﷺ,10. Hadith: Collection and Classification
|
||||||
8,1,Knowing the Creator,Ayatul Kursi
|
8,3,Challenges in Madinah,11. Hypocrites
|
||||||
8,2,Knowing the Messengerﷺ,The Person Muhammadﷺ
|
8,3,Challenges in Madinah,12. Banu Qaynuqa: Threat Within Madinah
|
||||||
8,2,Knowing the Messengerﷺ,Farewell Pilgrimage
|
8,3,Challenges in Madinah,13. Banu Nadir: Treachery Within Madinah
|
||||||
8,2,Knowing the Messengerﷺ,Finality of Prophethood
|
8,3,Challenges in Madinah,14. Banu Qurayzah
|
||||||
8,2,Knowing the Messengerﷺ,"Hadith: Collection, Classification"
|
8,3,Challenges in Madinah,15. Mission to Tabūk: A Test of Steadfastness
|
||||||
8,3,Challenges in Madinah,Hypocrites
|
8,4,Islamic Ethical Framework,16. Friends and Friendship: Who is a Good Friend?
|
||||||
8,3,Challenges in Madinah,Banu Qaynuqa
|
8,4,Islamic Ethical Framework,17. Friendship With Non-Muslims
|
||||||
8,3,Challenges in Madinah,Banu Nadir
|
8,4,Islamic Ethical Framework,18. Dating: How Islam Views the Practice
|
||||||
8,3,Challenges in Madinah,Banu Qurayzah
|
8,4,Islamic Ethical Framework,19. Hold Firmly the Rope of Allah
|
||||||
8,3,Challenges in Madinah,Mission to Tabuk
|
8,4,Islamic Ethical Framework,20. Elements of a Bad Life
|
||||||
8,4,Islamic Ethical Framework,Friends and Friendship
|
8,5,Islamic Values and Teachings,21. Duties Towards Parents
|
||||||
8,4,Islamic Ethical Framework,Friendship With Non-Muslims
|
8,5,Islamic Values and Teachings,22. Hope, Hopefulness, Hopelessness
|
||||||
8,4,Islamic Ethical Framework,Dating in Islam
|
8,5,Islamic Values and Teachings,23. Trials in Life: Everyone Will Experience Them
|
||||||
8,4,Islamic Ethical Framework,Hold Firmly the Rope of Allah
|
8,5,Islamic Values and Teachings,24. Permitted and Prohibited Food
|
||||||
8,4,Islamic Ethical Framework,Elements of Bad Life
|
8,5,Islamic Values and Teachings,25. Performance of Hajj
|
||||||
8,5,"Islamic Values, Teachings",Duties Toward Parents
|
8,5,Islamic Values and Teachings,26. Parables in the Qur’an
|
||||||
8,5,"Islamic Values, Teachings","Hope, Hopefulness, Hopelessness"
|
8,6,Islam After the Messenger ﷺ,27. Early History of Shi‘ah Muslims
|
||||||
8,5,"Islamic Values, Teachings",Trials in Life
|
8,6,Islam After the Messenger ﷺ,28. Umayyad Dynasty
|
||||||
8,5,"Islamic Values, Teachings",Permitted and Prohibited Food
|
8,6,Islam After the Messenger ﷺ,29. Abbasid Dynasty
|
||||||
8,5,"Islamic Values, Teachings",Performance of Hajj
|
9,1,A Reflection on the Divine,1. Signs of Allahﷻ in Nature
|
||||||
8,5,"Islamic Values, Teachings",Parables in the Qur’an
|
9,1,A Reflection on the Divine,2. Pondering the Qur’an
|
||||||
8,6,Islam After the Rasul (S),Origin and History of Shi‘ah
|
9,1,A Reflection on the Divine,3. Preservation and Compilation of the Qur’an
|
||||||
8,6,Islam After the Rasul (S),Ummayad Dynasty
|
9,1,A Reflection on the Divine,4. Ibadat—Easy Ways to Do It
|
||||||
8,6,Islam After the Rasul (S),Abbasid Dynasty
|
9,1,A Reflection on the Divine,5. Surah Baqarah—Statement of Faith and Commitment
|
||||||
9,1,A Reflection on the Divine,Signs of Allahﷻ in Nature
|
9,2,Islam and Muslim,6. Why Human Beings Are Superior
|
||||||
9,1,A Reflection on the Divine,Pondering the Qur’an
|
9,2,Islam and Muslim,7. Life Cycle of Truth
|
||||||
9,1,A Reflection on the Divine,Preservation and Compilation of the Qur’an
|
9,2,Islam and Muslim,8. Is Islam a Violent Religion?
|
||||||
9,1,A Reflection on the Divine,Ibadat—Easy Ways to Do It
|
9,2,Islam and Muslim,9. Present Life: Vanity, Deception, Play
|
||||||
9,1,A Reflection on the Divine,Surah Baqarah—Statement of Faith and Commitment
|
9,2,Islam and Muslim,10. Shariah
|
||||||
9,2,Islam and Muslim,Why Human Beings Are Superior
|
9,2,Islam and Muslim,11. Justice in Islam
|
||||||
9,2,Islam and Muslim,Life Cycle of Truth
|
9,3,Ethical Standard in Islam,12. Choices We Make
|
||||||
9,2,Islam and Muslim,Is Islam a Violent Religion?
|
9,3,Ethical Standard in Islam,13. Peer Pressure
|
||||||
9,2,Islam and Muslim,"Present Life: Vanity, Deception, Play"
|
9,3,Ethical Standard in Islam,14. Islamic Perspective on Dating
|
||||||
9,2,Islam and Muslim,Shariah
|
9,3,Ethical Standard in Islam,15. Indecency
|
||||||
9,2,Islam and Muslim,Justice in Islam
|
9,3,Ethical Standard in Islam,16. Alcohol and Gambling
|
||||||
9,3,Ethical Standard in Islam,Choices We Make
|
9,3,Ethical Standard in Islam,17. Permitted and Prohibited Food
|
||||||
9,3,Ethical Standard in Islam,Peer Pressure
|
9,3,Ethical Standard in Islam,18. Food of the People of the Book
|
||||||
9,3,Ethical Standard in Islam,Islamic Perspective on Dating
|
9,3,Ethical Standard in Islam,19. Let Ramadan Bring The Best in Us
|
||||||
9,3,Ethical Standard in Islam,Indecency
|
9,4,Essays on Rasulullahﷺ,20. Khadijah (ra)
|
||||||
9,3,Ethical Standard in Islam,Alcohol and Gambling
|
9,4,Essays on Rasulullahﷺ,21. Rasulullahﷺ Multiple Marriages
|
||||||
9,3,Ethical Standard in Islam,Permitted and Prohibited Food
|
9,4,Essays on Rasulullahﷺ,22. Marriage to Zainab (ra)
|
||||||
9,3,Ethical Standard in Islam,Food of the People of the Book
|
9,4,Essays on Rasulullahﷺ,23. Rasulullahﷺ: A Great Army General
|
||||||
9,3,Ethical Standard in Islam,Let Ramadan Bring The Best in Us
|
9,4,Essays on Rasulullahﷺ,24. Prophecy of Muhammadﷺ in the Bible
|
||||||
9,4,Essays on Rasulullahﷺ,Khadijah (ra)
|
9,4,Essays on Rasulullahﷺ,25. Allegations Against Rasulullahﷺ
|
||||||
9,4,Essays on Rasulullahﷺ,Rasulullahﷺ Multiple Marriages
|
9,5,Faith-Based Wealth Building,26. Faith Based Wealth Building
|
||||||
9,4,Essays on Rasulullahﷺ,Marriage to Zainab (ra)
|
9,5,Faith-Based Wealth Building,27. Earn, Save, Spend, Invest
|
||||||
9,4,Essays on Rasulullahﷺ,Rasulullahﷺ: A Great Army General
|
9,5,Faith-Based Wealth Building,28. Let Investment Work for You
|
||||||
9,4,Essays on Rasulullahﷺ,Prophecy of Muhammadﷺ in the Bible
|
|
||||||
9,4,Essays on Rasulullahﷺ,Allegations Against Rasulullahﷺ
|
|
||||||
9,5,Faith-Based Wealth Building,Faith Based Wealth Building
|
|
||||||
9,5,Faith-Based Wealth Building,"Earn, Save, Spend, Invest"
|
|
||||||
9,5,Faith-Based Wealth Building,Let Investment Work for You
|
|
||||||
|
|||||||
|
@@ -1,45 +0,0 @@
|
|||||||
Grade,Surah
|
|
||||||
1,Al-Fatihah
|
|
||||||
1,An-Nas
|
|
||||||
1,Al-Falaq
|
|
||||||
1,Al-Ikhlas
|
|
||||||
2,Al-Masad
|
|
||||||
2,An-Nasr
|
|
||||||
2,Al-Kafirun
|
|
||||||
2,Al-Kawthar
|
|
||||||
2,Al-Ma'un
|
|
||||||
3,Quraysh
|
|
||||||
3,Al-Fil
|
|
||||||
3,Al-Humazah
|
|
||||||
3,Al-'Asr
|
|
||||||
3,At-Takathur
|
|
||||||
4,Al-Qari'ah
|
|
||||||
4,Al-'Adiyat
|
|
||||||
4,Az-Zalzalah
|
|
||||||
4,Al-Bayyinah
|
|
||||||
4,Al-Qadr
|
|
||||||
5,Al-'Alaq
|
|
||||||
5,At-Tin
|
|
||||||
5,Ash-Sharh
|
|
||||||
5,Ad-Duhaa
|
|
||||||
5,Al-Layl
|
|
||||||
6,Ash-Shams
|
|
||||||
6,Al-Balad
|
|
||||||
6,Al-Fajr
|
|
||||||
6,Al-Ghashiyah
|
|
||||||
6,Al-A'la
|
|
||||||
7,At-Tariq
|
|
||||||
7,Al-Buruj
|
|
||||||
7,Al-Inshiqaq
|
|
||||||
7,Al-Mutaffifin
|
|
||||||
7,Al-Infitar
|
|
||||||
8,At-Takwir
|
|
||||||
8,Abasa
|
|
||||||
8,Al-Mursalat
|
|
||||||
8,An-Naba
|
|
||||||
9,Al-Mulk
|
|
||||||
9,Al-Qalam
|
|
||||||
9,Al-Haqqah
|
|
||||||
9,Al-Ma'arij
|
|
||||||
9,Nuh
|
|
||||||
9,Al-Jinn
|
|
||||||
|
Binary file not shown.
Reference in New Issue
Block a user