Skip to content

Commit

Permalink
Merge branch 'master' into snyk-upgrade-5eeaa187e11ac5f3cbe0771fda8ec424
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelfolaron authored Jun 10, 2024
2 parents 474f488 + ddaae67 commit f9ccdef
Show file tree
Hide file tree
Showing 56 changed files with 566 additions and 331 deletions.
10 changes: 10 additions & 0 deletions app/Core/ConsoleKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public static function artisanBinary()
});
}

/**
* Load and register the commands for the application.
*
* @return void
*/
protected function commands()
{
static $commandsLoaded;
Expand Down Expand Up @@ -181,6 +186,11 @@ protected function commands()
$commandsLoaded = true;
}

/**
* Schedule tasks to be executed.
*
* @return void
*/
private function schedule()
{
// Set default timezone
Expand Down
2 changes: 1 addition & 1 deletion app/Core/Middleware/InitialHeaders.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function handle(IncomingRequest $request, Closure $next): Response
"base-uri 'self';",
"script-src 'self' 'unsafe-inline' unpkg.com",
"font-src 'self' data:",
"img-src 'self' *.leantime.io data: blob:",
"img-src 'self' *.leantime.io *.amazonaws.com data: blob:",
"frame-src 'self' *.google.com *.microsoft.com *.live.com",
"frame-ancestors 'self' *.google.com *.microsoft.com *.live.com",
];
Expand Down
6 changes: 6 additions & 0 deletions app/Core/Middleware/Installed.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public function handle(IncomingRequest $request, Closure $next): Response

\Illuminate\Support\Facades\Cache::set('installed', true);

$route = Frontcontroller::getCurrentRoute();

if($session_says && $route == "install") {
return Frontcontroller::redirect(BASE_URL . "/auth/logout");
}

return $next($request);
}

Expand Down
50 changes: 43 additions & 7 deletions app/Core/Middleware/RequestRateLimiter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Closure;
use Illuminate\Cache\RateLimiter;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Support\Facades\Cache;
use Leantime\Core\ApiRequest;
use Leantime\Core\Environment;
use Leantime\Core\Eventhelpers;
use Leantime\Core\Frontcontroller;
use Leantime\Core\IncomingRequest;
Expand Down Expand Up @@ -41,29 +43,39 @@ public function __construct()
* Handle the incoming request.
*
* @param IncomingRequest $request The incoming request object.
* @param Closure $next The next middleware closure.
* @param Closure $next The next middleware closure.
* @return Response The response object.
* @throws BindingResolutionException
*/
public function handle(IncomingRequest $request, Closure $next): Response
{
//Configurable rate limits
$rateLimitGeneral = app()->make(Environment::class)->get('LEAN_RATELIMIT_GENERAL') ?? 1000;
$rateLimitApi = app()->make(Environment::class)->get('LEAN_RATELIMIT_API') ?? 10;
$rateLimitAuth = app()->make(Environment::class)->get('LEAN_RATELIMIT_AUTH') ?? 20;

//Key
$key = $request->getClientIp();
$keyModifier = "-1";
if(isset($_SESSION['userdata'])){
$keyModifier = $_SESSION['userdata']['id'];
}

$key = $request->getClientIp()."-".$keyModifier;

//General Limit per minute
$limit = 1000;
$limit = $rateLimitGeneral;

//API Routes Limit
if ($request instanceof ApiRequest) {
$apiKey = "";
$key = app()->make(Api::class)->getAPIKeyUser($apiKey);
$limit = 10;
$limit = $rateLimitApi;
}

$route = Frontcontroller::getCurrentRoute();

if ($route == "auth.login") {
$limit = 20;
$limit = $rateLimitAuth;
$key = $key . ".loginAttempts";
}

Expand All @@ -83,13 +95,37 @@ public function handle(IncomingRequest $request, Closure $next): Response
"key" => $key,
],
);

if ($this->limiter->tooManyAttempts($key, $limit)) {
error_log("too many requests per minute: " . $key);
return new Response(json_encode(['error' => 'Too many requests per minute.']), Response::HTTP_TOO_MANY_REQUESTS);
return new Response(
json_encode(['error' => 'Too many requests per minute.']),
Response::HTTP_TOO_MANY_REQUESTS,
$this->getHeaders($key, $limit),
);
}

$this->limiter->hit($key, 60);

return $next($request);
}


/**
* Get rate limiter headers for response.
*
* @param string $key
*
* @param string $limit
*
* @return array
*/
private function getHeaders(string $key, string $limit): array
{
return [
'X-RateLimit-Remaining' => $this->limiter->retriesLeft($key, $limit),
'X-RateLimit-Retry-After' => $this->limiter->availableIn($key),
'X-RateLimit-Limit' => $this->limiter->attempts($key),
'Retry-After' => $this->limiter->availableIn($key),
];
}
}
5 changes: 4 additions & 1 deletion app/Domain/Auth/Controllers/Login.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ public function get(array $params): Response
$url = urldecode($_GET['redirect']);

//Check for open redirects, don't allow redirects to external sites.
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
if (
filter_var($url, FILTER_VALIDATE_URL) === false &&
!in_array($url, ["/auth/logout"])
) {
$redirectUrl = BASE_URL ."/" . $url;
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/Domain/Install/Controllers/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function init(InstallRepository $installRepo)
$this->installRepo = $installRepo;

if ($this->installRepo->checkIfInstalled()) {
return FrontcontrollerCore::redirect(BASE_URL);
return FrontcontrollerCore::redirect(BASE_URL . "/");
}
}

Expand Down
25 changes: 14 additions & 11 deletions app/Domain/Menu/Repositories/Menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* menu class - Menu definitions
*/

namespace Leantime\Domain\Menu\Repositories {

use Leantime\Core\Environment as EnvironmentCore;
Expand Down Expand Up @@ -143,16 +144,12 @@ class Menu
public function __construct(
/** @var SettingRepository */
private SettingRepository $settingsRepo,

/** @var LanguageCore */
private LanguageCore $language,

/** @var EnvironmentCore */
private EnvironmentCore $config,

/** @var TicketService */
private TicketService $ticketsService,

/** @var AuthService */
private AuthService $authService,
) {
Expand Down Expand Up @@ -251,14 +248,21 @@ function: 'getMenuStructure'
public function getMenuStructure(string $menuType = ''): array
{
$language = $this->language;
$filter = "menuStructures.$menuType";

$menuCollection = collect($this->menuStructures)->map(
function ($menu) use ($menuType, $filter) {
return self::dispatch_filter(
$filter,
$this->buildMenuStructure($menu, $filter),
'getMenuStructure'
);
}
)->all();

$this->menuStructures = self::dispatch_filter(
'menuStructures',
collect($this->menuStructures)->map(fn ($menu, $menuType) => self::dispatch_filter(
hook: $filter = "menuStructures.$menuType",
payload: $this->buildMenuStructure($menu, $filter),
function: 'getMenuStructure'
))->all(),
$menuCollection,
['menuType' => $menuType]
);

Expand All @@ -275,8 +279,7 @@ function: 'getMenuStructure'
ksort($menuStructure);

foreach ($menuStructure as $key => $element) {

if(isset($menuStructure[$key]['title'])){
if (isset($menuStructure[$key]['title'])) {
$menuStructure[$key]['title'] = $language->__($element['title']);
}

Expand Down
49 changes: 49 additions & 0 deletions app/Domain/Plugins/Contracts/PluginInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Leantime\Domain\Plugins\Contracts;

/**
* Interface PluginInterface
*
* This interface represents a plugin that can be installed, uninstalled, enabled, and disabled.
*/
interface PluginInterface
{

/**
* Installs the plugin.
*
* @return bool True if the installation is successful, false otherwise.
*/
public function install(): bool;

/**
* Uninstalls the plugin.
*
* This method performs the necessary actions to uninstall the application and remove all associated files and data.
*
* @return bool Returns true if the uninstallation is successful, false otherwise.
*/
public function uninstall(): bool;

/**
* Enables the plugin.
*
* This method performs the necessary actions to enable the specified functionality. It may update configuration settings, start background processes, or perform any other actions required
* to enable the functionality.
*
* @return bool Returns true if the enable operation is successful, false otherwise.
*/
public function enable(): bool;

/**
* Disable the plugin.
*
* This method disables the functionality and returns a boolean value indicating whether the functionality is successfully disabled or not.
*
* @return bool True if the functionality is successfully disabled, false otherwise.
*/
public function disable(): bool;


}
1 change: 1 addition & 0 deletions app/Domain/Tickets/Repositories/Tickets.php
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ public function simpleTicketQuery(?int $userId, ?int $projectId): array|false
IF(zp_tickets.type <> "", zp_tickets.type, "task") AS type,
zp_tickets.status,
zp_tickets.tags,
zp_tickets.userId,
zp_tickets.editorId,
zp_tickets.dependingTicketId,
zp_tickets.milestoneid,
Expand Down
48 changes: 46 additions & 2 deletions app/Domain/Tickets/Services/Tickets.php
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,48 @@ public function getOpenUserTicketsByProject($userId, $projectId): array
return $tickets;
}

/**
* @param $userId
* @param $projectId
* @return array
*/
public function getOpenUserTicketsByPriority($userId, $projectId): array
{

$searchCriteria = $this->prepareTicketSearchArray(array("users" => $userId, "status" => "", "sprint" => ""));
$allTickets = $this->ticketRepository->getAllBySearchCriteria($searchCriteria, "priority");

$statusLabels = $this->getAllStatusLabelsByUserId($userId);

$tickets = array();

foreach ($allTickets as $row) {
//Only include todos that are not done
if (
isset($statusLabels[$row['projectId']]) &&
isset($statusLabels[$row['projectId']][$row['status']]) &&
$statusLabels[$row['projectId']][$row['status']]['statusType'] != "DONE"
) {
$label = $this->ticketRepository->priority[$row['priority']];
if (isset($tickets[$row['priority']])) {
$tickets[$row['priority']]['tickets'][] = $row;
} else {
// If the priority is not set, the label for priority not defined is used.
if (empty($this->ticketRepository->priority[$row['priority']])) {
$label =$this->language->__("label.priority_not_defined");
}
$tickets[$row['priority']] = array(
"labelName" =>$label,
"tickets" => array($row),
"groupValue" => $row['time'],
);
}
}
}

return $tickets;
}


/**
* @param $userId
Expand Down Expand Up @@ -1085,7 +1127,7 @@ public function quickAddTicket($params): array|bool

$values = array(
'headline' => $params['headline'],
'type' => 'Task',
'type' => 'task',
'description' => $params['description'] ?? '',
'projectId' => $params['projectId'] ?? $_SESSION['currentProject'],
'editorId' => $_SESSION['userdata']['id'],
Expand Down Expand Up @@ -1193,7 +1235,7 @@ public function addTicket($values)
$values = array(
'id' => '',
'headline' => $values['headline'] ?? "",
'type' => $values['type'] ?? "Task",
'type' => $values['type'] ?? "task",
'description' => $values['description'] ?? "",
'projectId' => $values['projectId'] ?? $_SESSION['currentProject'] ,
'editorId' => $values['editorId'] ?? "",
Expand Down Expand Up @@ -1941,6 +1983,8 @@ public function getToDoWidgetAssignments($params)
$tickets = $this->getOpenUserTicketsThisWeekAndLater($_SESSION["userdata"]["id"], $projectFilter);
} elseif ($groupBy == "project") {
$tickets = $this->getOpenUserTicketsByProject($_SESSION["userdata"]["id"], $projectFilter);
} elseif ($groupBy == "priority") {
$tickets = $this->getOpenUserTicketsByPriority($_SESSION["userdata"]["id"], $projectFilter);
} elseif ($groupBy == "sprint") {
$tickets = $this->getOpenUserTicketsBySprint($_SESSION["userdata"]["id"], $projectFilter);
}
Expand Down
16 changes: 16 additions & 0 deletions app/Domain/Widgets/Templates/partials/myToDos.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ class="btn btn-primary"
<label for="groupByProject">{!! __("label.project") !!}</label>
</span>
</li>
<li>
<span class="radio">
<input type="radio"
name="groupBy"
@if($groupBy == "priority") checked='checked' @endif
value="priority" id="groupByPriority"
hx-get="{{BASE_URL}}/widgets/myToDos/get"
hx-trigger="click"
hx-target="#yourToDoContainer"
hx-swap="outerHTML"
hx-indicator="#todos .htmx-indicator"
hx-vals='{"projectFilter": {{ $projectFilter }}, "groupBy": "priority" }'
/>
<label for="groupByPriority">{!! __("label.priority") !!}</label>
</span>
</li>

</ul>
</div>
Expand Down
1 change: 1 addition & 0 deletions app/Language/ar-SA.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,7 @@ dropdown.choose_list="List"
groupByLabel.sprint="List"
groupByLabel.project="Project"
groupByLabel.time="Due Date"
groupByLabel.priority="Priority"

label.sprint_dates="Sprint Dates"

Expand Down
1 change: 1 addition & 0 deletions app/Language/cs-CZ.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,7 @@ dropdown.choose_list="List"
groupByLabel.sprint="List"
groupByLabel.project="Project"
groupByLabel.time="Due Date"
groupByLabel.priority="Priority"

label.sprint_dates="Sprint Dates"

Expand Down
Loading

0 comments on commit f9ccdef

Please sign in to comment.