Rapikan tampilan nilai, ganti NPM->NIM, fitur ganti password, kunci RPS view-only

- Tampilan "Isi Per Komponen Penilaian" diganti dari tombol bertumpuk teks
  jadi tabel (Komponen/Sub-CPMK/Bobot/Status/Aksi) dengan status berupa
  stempel, lebih mudah dipindai.
- Filter pencarian MK (ketik kode/nama) di kotak penugasan dosen /admin.
- Istilah NPM diseragamkan jadi NIM di seluruh aplikasi (label, header,
  template Excel, dokumen portofolio), termasuk migrasi kolom database
  mahasiswa.npm -> nim yang aman (ALTER TABLE RENAME COLUMN, otomatis saat
  startup, tanpa kehilangan data; parser Excel tetap terima file lama
  berheader NPM).
- Fitur ganti password mandiri (/akun): verifikasi password lama, sesi lain
  otomatis keluar setelah berhasil, sesi yang dipakai tetap aktif.
- RPS: dosen RPS+MK kini bisa menyesuaikan redaksi kalimat Sub-CPMK (bagian
  D) untuk MK yang diampu -- kode & kaitan CPMK/CPL tetap dari kurikulum,
  hanya teksnya yang bisa disesuaikan. Penyesuaian otomatis konsisten di
  dropdown mingguan (F), checklist komponen (G), serta unduhan RPS &
  portofolio, tanpa menyentuh data kurikulum induk atau halaman nilai/
  dashboard prodi.
- Form RPS dibungkus <fieldset disabled> untuk dosen tanpa hak edit --
  seluruh field benar-benar terkunci (bukan cuma tombol simpan hilang).
This commit is contained in:
Power BI Dev
2026-07-22 08:37:54 +07:00
parent afb9e72ba2
commit 5f615aa7e8
12 changed files with 199 additions and 87 deletions
+14 -6
View File
@@ -138,6 +138,13 @@ def _migrasi_role_pengguna(conn: sqlite3.Connection) -> None:
conn.execute("DROP TABLE pengguna_lama")
def _migrasi_nim_mahasiswa(conn: sqlite3.Connection) -> None:
"""Kolom lama bernama 'npm' — istilah baku adalah NIM, bukan NPM."""
kolom = {r["name"] for r in conn.execute("PRAGMA table_info(mahasiswa)")}
if "npm" in kolom and "nim" not in kolom:
conn.execute("ALTER TABLE mahasiswa RENAME COLUMN npm TO nim")
def _migrasi_kelas_penugasan(conn: sqlite3.Connection) -> None:
"""Skema lama penugasan hanya (user_id, mk_kode) — tambah kolom kelas
(kosong = seluruh kelas MK ini, dipakai dosen_rps_mk; terisi = dosen_mk
@@ -207,14 +214,15 @@ def init_db() -> None:
_migrasi_kelas_penugasan(conn)
conn.execute(
"""CREATE TABLE IF NOT EXISTS mahasiswa (
npm TEXT NOT NULL,
nim TEXT NOT NULL,
nama TEXT NOT NULL,
mk_kode TEXT NOT NULL,
kelas TEXT NOT NULL DEFAULT '',
tahun TEXT NOT NULL,
PRIMARY KEY (npm, mk_kode, tahun)
PRIMARY KEY (nim, mk_kode, tahun)
)"""
)
_migrasi_nim_mahasiswa(conn)
# ── pengaturan prodi ─────────────────────────────────────────────────────────
@@ -507,9 +515,9 @@ def ganti_mahasiswa(baris: list[dict], tahun: str | None = None) -> None:
with get_conn() as conn:
conn.execute("DELETE FROM mahasiswa WHERE tahun=?", (tahun,))
conn.executemany(
"INSERT OR REPLACE INTO mahasiswa (npm, nama, mk_kode, kelas, tahun) "
"INSERT OR REPLACE INTO mahasiswa (nim, nama, mk_kode, kelas, tahun) "
"VALUES (?,?,?,?,?)",
[(b["npm"], b["nama"], b["mk_kode"], b.get("kelas", ""), tahun)
[(b["nim"], b["nama"], b["mk_kode"], b.get("kelas", ""), tahun)
for b in baris],
)
@@ -518,8 +526,8 @@ def mahasiswa_mk(mk_kode: str, tahun: str | None = None) -> list[dict]:
tahun = tahun or tahun_aktif()
with get_conn() as conn:
rows = conn.execute(
"SELECT npm, nama, kelas FROM mahasiswa WHERE mk_kode=? AND tahun=? "
"ORDER BY kelas, npm",
"SELECT nim, nama, kelas FROM mahasiswa WHERE mk_kode=? AND tahun=? "
"ORDER BY kelas, nim",
(mk_kode, tahun),
).fetchall()
return [dict(r) for r in rows]