Skip to content

Commit 7cb0199

Browse files
committed
Allow API to use any service and new api endpoints
1 parent 9ac2732 commit 7cb0199

File tree

20 files changed

+997
-422
lines changed

20 files changed

+997
-422
lines changed

app/Core/Middleware/ApiAuth.php

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Leantime\Core\Frontcontroller;
99
use Leantime\Core\IncomingRequest;
1010
use Leantime\Domain\Api\Services\Api as ApiService;
11+
use Leantime\Domain\Auth\Models\Roles;
1112
use Leantime\Domain\Auth\Services\Auth as AuthService;
1213
use Leantime\Domain\Projects\Services\Projects as ProjectsService;
1314
use Symfony\Component\HttpFoundation\Response;

app/Core/Middleware/InitialHeaders.php

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public function handle(IncomingRequest $request, Closure $next): Response
3131
"frame-src 'self' *.google.com *.microsoft.com *.live.com",
3232
"frame-ancestors 'self' *.google.com *.microsoft.com *.live.com",
3333
];
34+
$cspParts = self::dispatch_filter('cspParts', $cspParts);
3435
$csp = implode(";", $cspParts);
3536

3637
foreach (

app/Core/Session.php

Whitespace-only changes.

app/Core/Template.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,8 @@ public function displayJson(array|object|string $jsonContent, int $statusCode =
549549
$response->headers->set('Content-Type', 'application/json; charset=utf-8');
550550

551551
if (is_array($jsonContent) || is_object($jsonContent)) {
552-
$jsonContent = json_encode($jsonContent);
552+
$collection = collect($jsonContent);
553+
$jsonContent = $collection->toJson();
553554

554555
if (json_last_error() !== JSON_ERROR_NONE) {
555556
return $response;

app/Domain/Api/Controllers/Jsonrpc.php

+29-9
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,11 @@ private function executeApiRequest(array $params): Response
160160

161161
$jsonRpcVer = $params['jsonrpc'] ?? null;
162162

163+
$moduleName = Str::studly($methodparts['module']);
163164
$serviceName = Str::studly($methodparts['service']);
164165

165-
$domainServiceNamespace = app()->getNamespace() . "Domain\\$serviceName\\Services\\$serviceName";
166-
$pluginServiceNamespace = app()->getNamespace() . "Plugins\\$serviceName\\Services\\$serviceName";
166+
$domainServiceNamespace = app()->getNamespace() . "Domain\\$moduleName\\Services\\$serviceName";
167+
$pluginServiceNamespace = app()->getNamespace() . "Plugins\\$moduleName\\Services\\$serviceName";
167168

168169
$methodName = Str::camel($methodparts['method']);
169170

@@ -181,6 +182,9 @@ private function executeApiRequest(array $params): Response
181182
return $this->returnMethodNotFound("Method doesn't exist: $methodName", $id);
182183
}
183184

185+
//Check method attributes
186+
//TODO: Check if method is available for api
187+
184188
if ($jsonRpcVer == null) {
185189
return $this->returnInvalidRequest("You must include a \"jsonrpc\" parameter with a value of \"2.0\"", $id);
186190
}
@@ -204,7 +208,7 @@ private function executeApiRequest(array $params): Response
204208
// can be null
205209
try {
206210
$method_response = app()->make($serviceName)->$methodName(...$preparedParams);
207-
} catch (\Error $e) {
211+
} catch (Exception $e) {
208212
return $this->returnServerError($e, $id);
209213
}
210214

@@ -236,15 +240,31 @@ private function parseMethodString(string $methodstring): array
236240
throw new Exception("Method string doesn't start with \"leantime.rpc.\"");
237241
}
238242

243+
//method parameter breakdown
244+
//00000000.111.22222222.3333333333333.444444444444
245+
//leantime.rpc.{module}.{servicename}.{methodname}
239246
$methodStringPieces = explode('.', $methodstring);
240-
if (count($methodStringPieces) !== 4) {
241-
throw new Exception("Method is case sensitive and must follow the following naming convention: \"leantime.rpc.{servicename}.{methodname}\"");
247+
248+
if (count($methodStringPieces) !== 4 && count($methodStringPieces) !== 5) {
249+
throw new Exception("Method is case sensitive and must follow the following naming convention: \"leantime.rpc.{domain}.{servicename}.{methodname}\"");
250+
}
251+
252+
if (count($methodStringPieces) === 4){
253+
return [
254+
'module' => $methodStringPieces[2],
255+
'service' => $methodStringPieces[2],
256+
'method' => $methodStringPieces[3],
257+
];
258+
}
259+
260+
if (count($methodStringPieces) === 5){
261+
return [
262+
'module' => $methodStringPieces[2],
263+
'service' => $methodStringPieces[3],
264+
'method' => $methodStringPieces[4],
265+
];
242266
}
243267

244-
return [
245-
'service' => $methodStringPieces[2],
246-
'method' => $methodStringPieces[3],
247-
];
248268
}
249269

250270
/**

app/Domain/Api/Services/Api.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public function getAPIKeyUser(string $apiKey): bool|array
4444

4545
if (!is_array($apiKeyParts) || count($apiKeyParts) != 3) {
4646
report("Not a valid API Key format");
47-
4847
return false;
4948
}
5049

@@ -202,4 +201,8 @@ public function getCaseCorrectPathFromManifest(string $filepath): string|false
202201

203202
return $basePath . array_search($referenceValue, $correctManifest);
204203
}
204+
205+
public function healthCheck() {
206+
return true;
207+
}
205208
}

app/Domain/Comments/Repositories/Comments.php

+38-2
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public function editComment($text, $id): bool
262262
return $result;
263263
}
264264

265-
public function getAllAccountComments(): array|false
265+
public function getAllAccountComments(?int $projectId, ?int $moduleId): array|false
266266
{
267267
$sql = "SELECT comment.id,
268268
comment.module,
@@ -272,10 +272,46 @@ public function getAllAccountComments(): array|false
272272
comment.userId,
273273
comment.commentParent,
274274
comment.status
275-
FROM zp_comment as comment";
275+
FROM zp_comment as comment
276+
LEFT JOIN zp_tickets ON comment.moduleId = zp_tickets.id
277+
LEFT JOIN zp_canvas_items ON comment.moduleId = zp_tickets.id
278+
LEFT JOIN zp_canvas ON zp_canvas.id = zp_canvas_items.canvasId
279+
LEFT JOIN zp_projects ON zp_canvas.projectId = zp_projects.id OR zp_tickets.projectId = zp_projects.id
280+
WHERE zp_projects.id IN (SELECT projectId FROM zp_relationuserproject WHERE zp_relationuserproject.userId = :userId)
281+
OR zp_projects.psettings = 'all'
282+
OR (zp_projects.psettings = 'client' AND zp_projects.clientId = :clientId)
283+
OR (:requesterRole = 'admin' OR :requesterRole = 'manager') ";
284+
285+
if (isset($projectId) && $projectId > 0) {
286+
$sql .= " AND (zp_projects.id = :projectId)";
287+
}
288+
289+
if (isset($moduleId) && $moduleId > 0) {
290+
$sql .= " AND ( comment.moduleId = :moduleId)";
291+
}
292+
293+
$sql .= " GROUP BY comment.id";
276294

277295
$stmn = $this->db->database->prepare($sql);
278296

297+
$stmn->bindValue(':userId', session("userdata.id") ?? '-1', PDO::PARAM_INT);
298+
$stmn->bindValue(':clientId', session("userdata.clientId") ?? '-1', PDO::PARAM_INT);
299+
300+
301+
if (session()->exists("userdata")) {
302+
$stmn->bindValue(':requesterRole', session("userdata.role"), PDO::PARAM_INT);
303+
} else {
304+
$stmn->bindValue(':requesterRole', -1, PDO::PARAM_INT);
305+
}
306+
307+
if (isset($projectId) && $projectId > 0) {
308+
$stmn->bindValue(':projectId', $projectId, PDO::PARAM_INT);
309+
}
310+
311+
if (isset($moduleId) && $moduleId > 0) {
312+
$stmn->bindValue(':moduleId', $moduleId, PDO::PARAM_INT);
313+
}
314+
279315
$stmn->execute();
280316
$values = $stmn->fetchAll();
281317
$stmn->closeCursor();

app/Domain/Comments/Services/Comments.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,20 @@ public function deleteComment($commentId): bool
139139
return $this->commentRepository->deleteComment($commentId);
140140
}
141141

142-
public function pollComments(): array | false
142+
public function pollComments(?int $projectId = null, ?int $moduleId = null): array | false
143143
{
144-
return $this->commentRepository->getAllAccountComments();
144+
145+
$comments = $this->commentRepository->getAllAccountComments($projectId, $moduleId);
146+
147+
foreach ($comments as $key => $comment) {
148+
if(dtHelper()->isValidDateString($comment['date'])) {
149+
$comments[$key]['date'] = dtHelper()->parseDbDateTime($comment['date'])->toIso8601ZuluString();
150+
}else{
151+
$comments[$key]['date'] = null;
152+
}
153+
}
154+
155+
return $comments;
145156
}
146157
}
147158
}

app/Domain/Connector/Services/Connector.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,6 @@ private function parseMilestones($fields, $values)
566566
return $flags;
567567
}
568568

569-
570-
571569
public function importValues($fields, $values, $entity)
572570
{
573571

@@ -738,5 +736,6 @@ private function cacheSerializedFieldValues($fields, $values)
738736
session(["serFields" => $serializedFields]);
739737
session(["serValues" => $serializedValues]);
740738
}
739+
741740
}
742741
}

app/Domain/Goalcanvas/Repositories/Goalcanvas.php

+143-4
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public function getSingleCanvas($canvasId): false|array
165165
*
166166
* @return array|false
167167
*/
168-
public function getAllAccountGoals(): false|array
168+
public function getAllAccountGoals(?int $projectId, ?int $boardId): false|array
169169
{
170170
$sql = "SELECT
171171
zp_canvas_items.id,
@@ -202,19 +202,158 @@ public function getAllAccountGoals(): false|array
202202
zp_canvas_items.action,
203203
zp_canvas_items.assignedTo,
204204
zp_canvas_items.parent,
205-
zp_canvas_items.tags
205+
zp_canvas_items.tags,
206+
zp_canvas.projectId
206207
FROM
207208
zp_canvas_items
209+
LEFT JOIN zp_canvas ON zp_canvas_items.canvasId = zp_canvas.id
210+
LEFT JOIN zp_projects ON zp_canvas.projectId = zp_projects.id
211+
WHERE zp_canvas_items.box = 'goal' AND (
212+
zp_canvas.projectId IN (SELECT projectId FROM zp_relationuserproject WHERE zp_relationuserproject.userId = :userId)
213+
OR zp_projects.psettings = 'all'
214+
OR (zp_projects.psettings = 'client' AND zp_projects.clientId = :clientId)
215+
OR (:requesterRole = 'admin' OR :requesterRole = 'manager')
216+
)
217+
";
208218

209-
WHERE zp_canvas_items.box = 'goal'
219+
if (isset($projectId) && $projectId > 0) {
220+
$sql .= " AND (zp_canvas.projectId = :projectId)";
221+
}
210222

211-
";
223+
if (isset($boardId) && $boardId > 0) {
224+
$sql .= " AND (zp_canvas.id = :boardId)";
225+
}
212226

213227
$stmn = $this->db->database->prepare($sql);
228+
229+
if (session()->exists("userdata")) {
230+
$stmn->bindValue(':requesterRole', session("userdata.role"), PDO::PARAM_INT);
231+
} else {
232+
$stmn->bindValue(':requesterRole', -1, PDO::PARAM_INT);
233+
}
234+
235+
$stmn->bindValue(':clientId', session("userdata.clientId") ?? '-1', PDO::PARAM_INT);
236+
$stmn->bindValue(':userId', session("userdata.id") ?? '-1', PDO::PARAM_INT);
237+
238+
if (isset($projectId) && $projectId > 0) {
239+
$stmn->bindValue(':projectId', $projectId, PDO::PARAM_INT);
240+
}
241+
242+
if (isset($boardId) && $boardId > 0) {
243+
$stmn->bindValue(':boardId', $boardId, PDO::PARAM_INT);
244+
}
245+
214246
$stmn->execute();
215247
$values = $stmn->fetchAll();
216248
$stmn->closeCursor();
217249
return $values;
218250
}
251+
252+
/**
253+
* @param $values
254+
* @return false|string
255+
*/
256+
public function createGoal($values): false|string
257+
{
258+
259+
$query = "INSERT INTO zp_canvas_items (
260+
description,
261+
title,
262+
assumptions,
263+
data,
264+
conclusion,
265+
box,
266+
author,
267+
created,
268+
modified,
269+
canvasId,
270+
status,
271+
relates,
272+
milestoneId,
273+
kpi,
274+
data1,
275+
startDate,
276+
endDate,
277+
setting,
278+
metricType,
279+
impact,
280+
effort,
281+
probability,
282+
action,
283+
assignedTo,
284+
startValue,
285+
currentValue,
286+
endValue,
287+
parent,
288+
tags
289+
) VALUES (
290+
:description,
291+
:title,
292+
:assumptions,
293+
:data,
294+
:conclusion,
295+
:box,
296+
:author,
297+
NOW(),
298+
NOW(),
299+
:canvasId,
300+
:status,
301+
:relates,
302+
:milestoneId,
303+
:kpi,
304+
:data1,
305+
:startDate,
306+
:endDate,
307+
:setting,
308+
:metricType,
309+
:impact,
310+
:effort,
311+
:probability,
312+
:action,
313+
:assignedTo,
314+
:startValue,
315+
:currentValue,
316+
:endValue,
317+
:parent,
318+
:tags
319+
)";
320+
321+
$stmn = $this->db->database->prepare($query);
322+
323+
$stmn->bindValue(':description', $values['description'] ?? '', PDO::PARAM_STR);
324+
$stmn->bindValue(':title', $values['title'] ?? '', PDO::PARAM_STR);
325+
$stmn->bindValue(':assumptions', $values['assumptions'] ?? '', PDO::PARAM_STR);
326+
$stmn->bindValue(':data', $values['data'] ?? '', PDO::PARAM_STR);
327+
$stmn->bindValue(':conclusion', $values['conclusion'] ?? '', PDO::PARAM_STR);
328+
$stmn->bindValue(':box', $values['box'], PDO::PARAM_STR);
329+
$stmn->bindValue(':author', $values['author'], PDO::PARAM_INT);
330+
$stmn->bindValue(':canvasId', $values['canvasId'], PDO::PARAM_INT);
331+
$stmn->bindValue(':status', $values['status'] ?? '', PDO::PARAM_STR);
332+
$stmn->bindValue(':relates', $values['relates'] ?? '', PDO::PARAM_STR);
333+
$stmn->bindValue(':milestoneId', $values['milestoneId'] ?? "", PDO::PARAM_STR);
334+
$stmn->bindValue(':kpi', $values['kpi'] ?? '', PDO::PARAM_STR);
335+
$stmn->bindValue(':data1', $values['data1'] ?? '', PDO::PARAM_STR);
336+
$stmn->bindValue(':startDate', $values['startDate'] ?? '', PDO::PARAM_STR);
337+
$stmn->bindValue(':endDate', $values['endDate'] ?? '', PDO::PARAM_STR);
338+
$stmn->bindValue(':setting', $values['setting'] ?? '', PDO::PARAM_STR);
339+
$stmn->bindValue(':metricType', $values['metricType'] ?? '', PDO::PARAM_STR);
340+
$stmn->bindValue(':impact', $values['impact'] ?? '', PDO::PARAM_STR);
341+
$stmn->bindValue(':effort', $values['effort'] ?? '', PDO::PARAM_STR);
342+
$stmn->bindValue(':probability', $values['probability'] ?? '', PDO::PARAM_STR);
343+
$stmn->bindValue(':action', $values['action'] ?? '', PDO::PARAM_STR);
344+
$stmn->bindValue(':assignedTo', $values['assignedTo'] ?? '', PDO::PARAM_STR);
345+
$stmn->bindValue(':startValue', $values['startValue'] ?? '', PDO::PARAM_STR);
346+
$stmn->bindValue(':currentValue', $values['currentValue'] ?? '', PDO::PARAM_STR);
347+
$stmn->bindValue(':endValue', $values['endValue'] ?? '', PDO::PARAM_STR);
348+
$stmn->bindValue(':parent', $values['parent'] ?? '', PDO::PARAM_STR);
349+
$stmn->bindValue(':tags', $values['tags'] ?? '', PDO::PARAM_STR);
350+
351+
$stmn->execute();
352+
$id = $this->db->database->lastInsertId();
353+
$stmn->closeCursor();
354+
355+
return $id;
356+
}
357+
219358
}
220359
}

0 commit comments

Comments
 (0)