Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 76 additions & 27 deletions document_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,30 +202,71 @@ def resolve(self) -> PHPExpression:
def __str__(self) -> str:
return f"{self.classname}::{self.funcname}()"

class PHPEnumFormat(PHPClassMemberFunction, PHPString):
def resolve(self) -> PHPString:
class PHPEnum():
@classmethod
def getcases(cls, classname: str) -> dict[str, str]:
# https://regex101.com/r/p5FzCh
casepattern = r"const (\w+) = (\d+|true|false|(['\"]).*?\3)"

fullbody_pattern = f"class {self.classname} extends Enum {{.*?}}"
fullbody_pattern = f"class {classname} extends (Enum|\\w+) {{(.*?)}}"

cases = {}

fp = f"lbplanner/classes/enums/{self.classname}.php"
fp = f"lbplanner/classes/enums/{classname}.php"
if not path.exists(fp):
warn(f"Couldn't find enum file {fp}")
return PHPStringLiteral("")
return {}
with open(fp, "r") as f:
matches: list[str] = re.findall(fullbody_pattern, f.read(), re.DOTALL)
matches: list[list[str]] = re.findall(fullbody_pattern, f.read(), re.DOTALL)
if len(matches) == 1:
body = matches[0]
if matches[0][0] != 'Enum':
cases = cls.getcases(matches[0][0])
body = matches[0][1]
else:
warn(f"couldn't parse enum {self.classname}", matches)
warn(f"couldn't parse enum {classname}", matches)

cases = {}
matches = re.findall(casepattern, body)
for match in matches:
# capitalizing first letter, if exists
name = "".join([match[0][0].upper(), match[0][1:].lower()])
cases[name] = match[1].replace("'", '"')
matches2: list[str] = re.findall(casepattern, body)
for match in matches2:
val = match[1].replace("'", '"')
cases[match[0]] = val

return cases

class PHPEnumCase(PHPEnum, PHPString):
__slots__ = ('classname', 'casename', 'fp')
classname: str
casename: str
fp: str

def __init__(self, classname: str, casename: str, fp: str):
self.classname = classname
self.casename = casename
self.fp = fp

def resolve(self) -> PHPString:
cases = self.getcases(self.classname)
if self.casename not in cases.keys():
warn(f"enum member {self.classname}::{self.casename} not found", cases)
return PHPStringLiteral("?")

val = cases[self.casename]

if val.startswith('"') and val.endswith('"'):
val = val[1:-1]

return PHPStringLiteral(val)

def get_value(self) -> str:
return self.resolve().get_value()

def __str__(self) -> str:
return f"{self.classname}::{self.casename}"

class PHPEnumFormat(PHPEnum, PHPClassMemberFunction, PHPString):
def resolve(self) -> PHPString:
cases = self.getcases(self.classname)
# capitalizing first letter of each key
cases = {"".join([name[0].upper(), name[1:].lower()]): case for name, case in cases.items()}

return PHPStringLiteral("{ " + ", ".join([f"{name} = {value}" for name, value in cases.items()]) + " }")

Expand Down Expand Up @@ -506,22 +547,30 @@ def parse_expression(code: str, nr: PHPNameResolution) -> tuple[int, PHPExpressi
assert len(buf) > 0
assert expr is None
i += 2
iplus = code[i:].index('(')
funcname = code[i:i + iplus]
iplus = 1
while 95 <= ord(code[i + iplus].lower()) <= 122: # until it hits non-word character
iplus += 1
is_func = code[i + iplus] == '('
membername = code[i:i + iplus]
classname = "".join(buf)
i += iplus
assert code[i:i + 2] == '()'
i += 2
C: type[PHPClassMemberFunction]
fp_import: str | None
if funcname == 'format':
C = PHPEnumFormat
fp_import = path.join(path.dirname(__file__), "lbplanner", "enums", f"{classname}.php")
if is_func:
assert code[i:i + 2] == '()'
i += 2
C: type[PHPClassMemberFunction]
fp_import: str | None
if membername == 'format':
C = PHPEnumFormat
fp_import = path.join(path.dirname(__file__), "lbplanner", "enums", f"{classname}.php")
else:
C = PHPClassMemberFunction
fp_import = find_import(nr, classname)
expr = C(classname, membername, fp_import).resolve()
buf = []
else:
C = PHPClassMemberFunction
fp_import = find_import(nr, classname)
expr = C(classname, funcname, fp_import).resolve()
buf = []
fp_import = path.join(path.dirname(__file__), "lbplanner", "enums", f"{classname}.php")
expr = PHPEnumCase(classname, membername, fp_import).resolve()
buf = []
else:
# unkown character? simply bail
if len(buf) > 0:
Expand Down
63 changes: 63 additions & 0 deletions lbplanner/classes/enums/KANBANCOL_TYPE.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
// This file is part of the local_lbplanner.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* enum for columns on the kanban board
*
* @package local_lbplanner
* @subpackage enums
* @copyright 2025 NecodeIT
* @license https://creativecommons.org/licenses/by-nc-sa/4.0/ CC-BY-NC-SA 4.0 International or later
*/

namespace local_lbplanner\enums;

// TODO: revert to native enums once we migrate to php8.

use local_lbplanner\polyfill\Enum;
use local_lbplanner\enums\KANBANCOL_TYPE_NUMERIC;

/**
* The types of columns in the kanban board
*/
class KANBANCOL_TYPE extends Enum {
/**
* column "backlog"
*/
const BACKLOG = 'backlog';
/**
* column "in progress"
*/
const INPROGRESS = 'inprogress';
/**
* column "todo"
*/
const TODO = 'todo';
/**
* column "done"
*/
const DONE = 'done';

/**
* Converts from column name to column ID
* @param string $str the column name
* @return int the column ID
* @link KANBANCOL_TYPE_NUMERIC
*/
public static function to_numeric(string $str): int {
return KANBANCOL_TYPE_NUMERIC::get(self::name_from($str));
}
}
63 changes: 63 additions & 0 deletions lbplanner/classes/enums/KANBANCOL_TYPE_NUMERIC.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
// This file is part of the local_lbplanner.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* enum for columns on the kanban board
*
* @package local_lbplanner
* @subpackage enums
* @copyright 2025 NecodeIT
* @license https://creativecommons.org/licenses/by-nc-sa/4.0/ CC-BY-NC-SA 4.0 International or later
*/

namespace local_lbplanner\enums;

// TODO: revert to native enums once we migrate to php8.

use local_lbplanner\polyfill\Enum;
use local_lbplanner\enums\KANBANCOL_TYPE;

/**
* The types of columns in the kanban board
*/
class KANBANCOL_TYPE_NUMERIC extends Enum {
/**
* column "backlog"
*/
const BACKLOG = 0;
/**
* column "todo"
*/
const TODO = 1;
/**
* column "in progress"
*/
const INPROGRESS = 2;
/**
* column "done"
*/
const DONE = 3;

/**
* converts numeric repr to named repr
* @param int $num the column number
* @return string the column name
* @link KANBANCOL_TYPE
*/
public static function to_named(int $num): string {
return KANBANCOL_TYPE::get(self::name_from($num));
}
}
39 changes: 39 additions & 0 deletions lbplanner/classes/enums/KANBANCOL_TYPE_ORNONE.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
// This file is part of the local_lbplanner.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* enum for columns on the kanban board
*
* @package local_lbplanner
* @subpackage enums
* @copyright 2025 NecodeIT
* @license https://creativecommons.org/licenses/by-nc-sa/4.0/ CC-BY-NC-SA 4.0 International or later
*/

namespace local_lbplanner\enums;
use local_lbplanner\enums\KANBANCOL_TYPE;

// TODO: revert to native enums once we migrate to php8.

/**
* The types of columns in the kanban board
*/
class KANBANCOL_TYPE_ORNONE extends KANBANCOL_TYPE {
/**
* nonexistant column - for user setting "don't move to any column"
*/
const NONE = '';
}
83 changes: 83 additions & 0 deletions lbplanner/classes/helpers/kanban_helper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
// This file is part of the local_lbplanner.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace local_lbplanner\helpers;

use local_lbplanner\enums\KANBANCOL_TYPE_NUMERIC;
use local_lbplanner\model\kanbanentry;

/**
* Helper class for the kanban board
*
* @package local_lbplanner
* @subpackage helpers
* @copyright 2025 NecodeIT
* @license https://creativecommons.org/licenses/by-nc-sa/4.0/ CC-BY-NC-SA 4.0 International or later
*/
class kanban_helper {

/**
* Table for storing kanban board entries.
*/
const TABLE = 'local_lbplanner_kanbanentries';

/**
* Gets all kanban entries for a user.
* @param int $userid ID of the user to look entries up for
* @return kanbanentry[] all the kanban entries for this user
*/
public static function get_all_entries_by_user(int $userid): array {
global $DB;

$res = $DB->get_records(self::TABLE, ['userid' => $userid]);
$entries = [];
foreach ($res as $obj) {
array_push($entries, kanbanentry::from_obj($obj));
}

return $entries;
}

/**
* Gets specific kanban entry.
* @param int $userid ID of the user to look entries up for
* @param int $cmid ID of the content-module
* @return kanbanentry the kanban entry matching this selection or null if not found
*/
public static function get_entry(int $userid, int $cmid): ?kanbanentry {
global $DB;

$res = $DB->get_record(self::TABLE, ['userid' => $userid, 'cmid' => $cmid]);

return $res !== false ? kanbanentry::from_obj($res) : null;
}

/**
* Sets specific kanban entry.
* @param kanbanentry $entry the entry to set
*/
public static function set_entry(kanbanentry $entry): void {
global $DB, $CFG;

$DB->delete_records(self::TABLE, ['userid' => $entry->userid, 'cmid' => $entry->cmid]);
if ($entry->column !== KANBANCOL_TYPE_NUMERIC::BACKLOG) {
$table = $CFG->prefix . self::TABLE;
// Moodle is too stupid to compensate for 'column' being a keyword so I need to shit my own ass manually.
$newid = $DB->execute("INSERT INTO {$table} VALUES (null,?,?,?)", [$entry->userid, $entry->cmid, $entry->column]);
$entry->set_fresh($newid);
}
}
}
2 changes: 1 addition & 1 deletion lbplanner/classes/helpers/user_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static function get_user(int $userid): user {
}

// Register user if not found.
$eduplanneruser = new user(0, $userid, 'default', 'none', 1, false);
$eduplanneruser = new user(0, $userid, 'default', 'none', 1, false, true, null, null, null);
$epid = $DB->insert_record(self::EDUPLANNER_USER_TABLE, $eduplanneruser->prepare_for_db());
$eduplanneruser->set_fresh($epid);

Expand Down
Loading
Loading