First prototypes

This commit is contained in:
Yasin İLKAYA 2025-12-21 01:49:30 +03:00
parent 397ee75b2e
commit 58b5ddb660
12 changed files with 233 additions and 26 deletions

19
Eksikler.md Normal file
View File

@ -0,0 +1,19 @@
+ Login
+ Register
+ Logout
- Profile edit
+ Add catalog (validation eksik)
+ List catalog
+ Update catalog
+ Delete catalog
+ Add student (validation eksik)
+ List student
+ Update student
+ Delete student
+ Add event
+ List event
- Update event Yapılmadı
+ Delete event

View File

@ -11,6 +11,7 @@ Application.get("/register", RegisterPage);
Application.post("/login", PostDataProcess(), Login);
Application.post("/register", PostDataProcess(), Register);
Application.get("/logout", MiddlewareAuth, Logout);
/**
* @param {import("express").Request} request
@ -184,4 +185,17 @@ function MiddlewareAuth(request, response, next)
}
}
exports.MiddlewareAuth = MiddlewareAuth;
exports.MiddlewareAuth = MiddlewareAuth;
/**
* @param {import("express").Request} request
* @param {import("express").Response} response
*/
function Logout(request, response)
{
request.session.authendicated = false;
request.session.user_id = null;
request.session.user = null;
request.session.save();
response.redirect(307,"/login");
}

View File

@ -115,7 +115,7 @@ function catalogStoreValidation(body)
const schema = Joi.object({
id: Joi.number().min(1),
name: Joi.string().min(3).max(200).required().error(new Error('Adı en az 3 karakter ve zorunludur')),
score: Joi.number().min(1).allow('', null).error(new Error('Soyadı formatı hatalı')),
score: Joi.number().allow('', null).error(new Error('Puan formatı hatalı')),
description: Joi.string().allow('', null)
});
const {error} = schema.validate(body);

View File

@ -3,7 +3,7 @@ const Joi = require("joi");
const { PostDataProcess } = require("../core/postdata");
const User = require("../database/user");
const { MiddlewareAuth } = require("./auth");
const { createStudent, getStudents, countStudents, updateStudent, deleteStudent, createEvent, getEvents, countEvents } = require("../database/student");
const { createStudent, getStudents, countStudents, updateStudent, deleteStudent, createEvent, getEvents, countEvents, deleteEvent, getStudentScores } = require("../database/student");
const express = require("express");
@ -248,4 +248,50 @@ async function EventsList(request, response)
"recordsFiltered" : count,
"data": data
});
}
Application.post("/events/destroy", MiddlewareAuth, express.urlencoded({extended: true}), EventDestroy);
/**
* @param {import("express").Request} request
* @param {import("express").Response} response
*/
async function EventDestroy(request, response)
{
try{
await deleteEvent(
request.session.user_id,
request.body.id ?? -1
);
return response.status(200).json({
status: "success"
});
}catch(err){
console.log(err)
return response.status(500).json({
status: "fail"
});
}
}
Application.post("/events/students", MiddlewareAuth, express.urlencoded({extended: true}), EventsStudents);
/**
* @param {import("express").Request} request
* @param {import("express").Response} response
*/
async function EventsStudents(request, response)
{
let start = request.body.start ?? 0;
let length = request.body.length ?? 100;
let term = request.body.search?.value ?? null;
let data = await getStudentScores(request.session.user_id,start,length, term);
response.json({
"draw": request.body.draw | 0,
"recordsTotal": data.length,
"recordsFiltered" : data.length,
"data": data
});
}

View File

@ -54,6 +54,7 @@ async function getCatalogs(
.where("owner_id",owner_id)
.whereNull("deleted_at")
.where("name","like",`%${searchTerm ?? ""}%`)
.orderBy("score","desc")
.limit(limit)
.offset(offset);
}

View File

@ -11,6 +11,8 @@ exports.deleteStudent = deleteStudent;
exports.createEvent = createEvent;
exports.countEvents = countEvents;
exports.getEvents = getEvents;
exports.deleteEvent = deleteEvent;
exports.getStudentScores = getStudentScores;
@ -79,6 +81,7 @@ async function getStudents(
.where("owner_id",owner_id)
.whereNull("deleted_at")
.where("name","like",`%${searchTerm ?? ""}%`)
.orderBy("created_at","desc")
.limit(limit)
.offset(offset);
}
@ -133,6 +136,7 @@ async function getEvents(owner_id,start,length,searchTerm)
{
return await DB
.select([
"student_events.id as id",
"students.name as studentname",
"students.surname as studentsurname",
"student_events.score",
@ -148,6 +152,41 @@ async function getEvents(owner_id,start,length,searchTerm)
q.orWhere("events.name","like",`%${searchTerm ?? ""}%`)
})
.orderBy("student_events.created_at","desc")
.whereNull("student_events.deleted_at")
.whereNull("students.deleted_at")
.whereNull("events.deleted_at")
.limit(length)
.offset(start);
}
async function getStudentScores(owner_id, start, length, searchTerm)
{
const students = await DB('students')
.select([
'id',
'name',
'surname',
DB('student_events')
.sum('score')
.whereRaw('?? = ??', ['student_events.student_id', 'students.id'])
.where('owner_id', owner_id)
.whereNull('deleted_at')
.as('total_score')
])
.where("name","like",`%${searchTerm ?? ""}%`)
.whereNull('deleted_at')
.orderBy('total_score', 'desc')
.limit(length)
.offset(start);
return students;
}
async function deleteEvent(owner_id, id)
{
await DB.table("student_events")
.where("owner_id",owner_id)
.where("id",id)
.update({
deleted_at: DB.fn.now()
});
}

View File

@ -49,7 +49,7 @@ function setUpHorizontalHeader() {
}
$(document).on('click', '.menu-previous', function (e) {
let layoutOption = getLocalStorageItem("layout-option","ltr");
let layoutOption = localStorage["layout-option"] ?? "ltr";
let attribute = (layoutOption == 'ltr' || layoutOption == 'box-layout') ? 'marginLeft' : 'marginRight';
let currentPosition = parseInt(navBar.css(attribute));
if (currentPosition < 0) {
@ -63,7 +63,7 @@ $(document).on('click', '.menu-previous', function (e) {
})
$(document).on('click', '.menu-next', function (e) {
let layoutOption = getLocalStorageItem("layout-option","ltr");
let layoutOption = localStorage["layout-option"] ?? "ltr";
let attribute = (layoutOption == 'ltr' || layoutOption == 'box-layout') ? 'marginLeft' : 'marginRight';
let currentPosition = parseInt(navBar.css(attribute));
if (currentPosition >= maxNavbarLimit) {
@ -78,9 +78,10 @@ $(document).on('click', '.menu-next', function (e) {
$(function () {
setUpHorizontalHeader();
let themeMode = getLocalStorageItem('theme-mode', 'light')
setTimeout(() => {
let themeMode = localStorage["theme-mode"] ?? "light";
$('body').addClass(`${themeMode}`)
setTimeout(() => {
$('body').addClass(`${themeMode}`)
}, 1500);
});
@ -265,7 +266,7 @@ if (themeToggle) {
const isDark = document.body.classList.contains("dark");
document.body.classList.toggle("dark", !isDark);
document.body.classList.toggle("light", isDark);
setLocalStorageItem('theme-mode', isDark ? 'light' : 'dark');
localStorage['theme-mode'] = isDark ? 'light' : 'dark';
});
}
function appendHtml() {

View File

@ -52,11 +52,11 @@
<div class="row app-form">
<div class="col-md-6 mt-3">
<label class="form-label">Aktivite Adı <small class="text-danger">*</small></label>
<input type="text" class="form-control" name="name" placeholder="Aktivite Adı" required min="3">
<input type="text" class="form-control" name="name" placeholder="Aktivite Adı" required minlength="3">
</div>
<div class="col-md-6 mt-3">
<label class="form-label">Puanı <small class="text-danger">*</small></label>
<input type="number" class="form-control" name="score" placeholder="Skor değeri" min="0" step="1" value="10" required>
<input type="number" class="form-control" name="score" placeholder="Skor değeri" step="1" value="10" required>
</div>
</div>
</form>
@ -71,7 +71,7 @@
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Öğrenci güncelle</h5>
<h5 class="modal-title">Katalog güncelle</h5>
<button aria-label="Close" class="btn-close m-0 fs-5" data-bs-dismiss="modal" type="button"></button>
</div>
<form class="modal-body" id="catalogupdateform" onsubmit="updateCatalog(this);return false;">
@ -79,7 +79,7 @@
<div class="row app-form">
<div class="col-md-6 mt-3">
<label class="form-label">Aktivite Adı <small class="text-danger">*</small></label>
<input type="text" class="form-control" name="name" placeholder="Aktivite Adı" required min="3">
<input type="text" class="form-control" name="name" placeholder="Aktivite Adı" required minlength="3">
</div>
<div class="col-md-6 mt-3">
<label class="form-label">Puanı <small class="text-danger">*</small></label>
@ -122,7 +122,10 @@
{
title: "Skor",
data: "score",
name: "score"
name: "score",
render:e => {
return e < 0 ? `<span class="text-danger">${e.toString()}</span>` : `<span class="text-success">+${e}</span>`
}
},
{
title: "Tarih",

View File

@ -3,10 +3,92 @@
<div class="app-content">
<%-include("../partials/navbar.ejs") %>
<main>
<h1>Merhaba</h1>
<div class="container-fluid">
<div class="row m-1">
<div class="col-12">
<h4 class="main-title text-center">
Öğrenci Skor Tablosu
</h4>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card ">
<div class="card-body p-0">
<div class="app-datatable-default overflow-auto">
<table class="table display app-data-table default-data-table" id="eventslist"></table>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<div aria-hidden="true" class="modal fade" id="add_event" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Yeni Skor Ekle</h5>
<button aria-label="Close" class="btn-close m-0 fs-5" data-bs-dismiss="modal" type="button"></button>
</div>
<form class="modal-body" id="eventsaveform" onsubmit="saveEvent(this);return false;">
<div class="row app-form">
<div class="col-md-6 mt-3">
<label class="form-label">Öğrenci</label>
<select name="student" class="form-control student" required></select>
</div>
<div class="col-md-6 mt-3">
<label class="form-label">Puan Kataloğu</label>
<select name="catalog" class="form-control catalog" required></select>
</div>
</div>
</form>
<div class="modal-footer">
<button class="btn btn-outline-success" type="submit" form="eventsaveform">Kaydet</button>
<button class="btn btn-light-secondary" data-bs-dismiss="modal" type="button">Kapat</button>
</div>
</div>
</div>
</div>
<script>
let dataTable;
$(function(){
dataTable = $("#eventslist").DataTable({
serverSide: true,
processing: true,
autoWidth: false,
ajax: {
url: "/events/students",
method:"post"
},
columns: [
{
width: "1%",
title: "#",
data: null,
render: function (data, type, row, meta) {
return meta.row + 1;
}
},
{
title: "Öğrenci",
data: null,
name: "fullname",
render: function (data, row) {
return `${data.name} ${data.surname || ''}`;
}
},
{
title: "Toplam Puanı",
data: "total_score",
name: "total_score"
}
],
"language": {
"url": "https://cdn.datatables.net/plug-ins/1.13.6/i18n/tr.json"
}
});
});
</script>
<%-include("../partials/footer.ejs") %>

View File

@ -5,7 +5,6 @@
<main>
<div class="container-fluid">
<!-- Breadcrumb start -->
<div class="row m-1">
<div class="col-12">
<h4 class="main-title">Öğrenci Skorları Geçmişi</h4>
@ -93,7 +92,7 @@
results: data.data.map(e => {
return {
id: e.id,
text: e.name + ` (+${e.score})`
text: e.name + ` (${e.score < 0 ? e.score : "+" + e.score})`
}
})
};
@ -175,7 +174,10 @@
{
title: "Puan",
data: "score",
name: "score"
name: "score",
render:e => {
return e < 0 ? `<span class="text-danger">${e.toString()}</span>` : `<span class="text-success">+${e}</span>`
}
},
{
title: "Tarih",
@ -191,7 +193,7 @@
render: function (data) {
return `
<div class="btn-group d-flex flex-row flex-nowrap" role="group">
<button class="btn btn-sm btn-outline-danger text-nowrap" onclick="deleteStudent(${data.id})" title="Sil">
<button class="btn btn-sm btn-outline-danger text-nowrap" onclick="deleteEvent(${data.id})" title="Sil">
<i class="fa fa-trash"></i>
Sil
</button>
@ -223,12 +225,12 @@
},
});
}
async function deleteStudent(id)
async function deleteEvent(id)
{
if(confirm("Kaydı silmek istediğinize emin misiniz?"))
{
$.ajax({
url: "/students/destroy",
url: "/events/destroy",
type: "post",
data: {
id

View File

@ -52,7 +52,7 @@
<div class="row app-form">
<div class="col-md-6 mt-3">
<label class="form-label">Adı <small class="text-danger">*</small></label>
<input type="text" class="form-control" name="name" placeholder="Öğrencinin adı" required min="3">
<input type="text" class="form-control" name="name" placeholder="Öğrencinin adı" required minlength="3">
</div>
<div class="col-md-6 mt-3">
<label class="form-label">Soyadı</label>
@ -103,7 +103,7 @@
<div class="row app-form">
<div class="col-md-6 mt-3">
<label class="form-label">Adı <small class="text-danger">*</small></label>
<input type="text" class="form-control" name="name" placeholder="Öğrencinin adı" required min="3">
<input type="text" class="form-control" name="name" placeholder="Öğrencinin adı" required minlength="3">
</div>
<div class="col-md-6 mt-3">
<label class="form-label">Soyadı</label>

View File

@ -74,7 +74,7 @@
</a>
</li>
<li class="no-sub text-danger">
<a href="/profile" class=" text-danger">
<a href="/logout" class=" text-danger">
<svg stroke="currentColor" stroke-width="1.5">
</svg>
Çıkış yap