feat: Implement email task import functionality

- Added `import_tasks_from_email` method in `Cron` class to handle task imports from email.
- Created `MailToTaskImporter` class for processing emails and creating tasks based on their content.
- Updated configuration to include IMAP settings for email import.
- Enhanced `Tasks` class with a method to change the client associated with a task.
- Modified task details view to include a dropdown for selecting clients.
- Improved task timer functionality with separate start and stop functions.
- Added logic to handle task work duration validation.
- Updated JavaScript to manage task timers and client changes more effectively.
This commit is contained in:
2026-02-07 00:53:48 +01:00
parent 47ffc19a23
commit ba84cdab3d
10 changed files with 983 additions and 90 deletions

View File

@@ -247,6 +247,10 @@ class Projects
public static function task_delete( $task_id )
{
global $mdb;
$attachments_repository = new \Domain\Tasks\TaskAttachmentRepository( $mdb );
$attachments_repository -> purgeByTaskId( (int)$task_id );
return $mdb -> update( 'tasks', [ 'deleted' => 1 ], [ 'id' => $task_id ] );
}

View File

@@ -3,6 +3,8 @@ namespace factory;
class Tasks
{
private const MIN_WORK_LOG_SECONDS = 60;
public static $statuses = [ 0 => 'nowe', 3 => 'do rozliczenia', 5 => 'do zrobienia', 1 => 'do sprawdzenia', 2 => 'zamknięte' ];
public static $priorities = [ 0 => 'niski', 1 => 'normalny', 2 => 'wysoki', 3 => 'pilny' ];
@@ -300,14 +302,32 @@ class Tasks
{
global $mdb;
$mdb -> update( 'tasks_work', [
'date_end' => date( 'Y-m-d H:i:s' )
], [
'AND' => [
'date_end' => null,
'user_id' => $user_id
]
] );
$open_works = $mdb -> select( 'tasks_work', [ 'id', 'date_start' ], [
'AND' => [
'date_end' => null,
'user_id' => $user_id,
'deleted' => 0
]
] );
if ( is_array( $open_works ) and count( $open_works ) )
{
$date_end_now = date( 'Y-m-d H:i:s' );
foreach ( $open_works as $open_work )
{
$work_id = isset( $open_work['id'] ) ? (int)$open_work['id'] : 0;
if ( !$work_id )
continue;
$is_too_short = self::is_work_duration_too_short( isset( $open_work['date_start'] ) ? $open_work['date_start'] : null, $date_end_now );
$mdb -> update( 'tasks_work', [
'date_end' => $date_end_now,
'deleted' => $is_too_short ? 1 : 0
], [ 'id' => $work_id ] );
}
}
$mdb -> insert( 'tasks_work', [
'user_id' => $user_id,
@@ -321,18 +341,41 @@ class Tasks
{
global $mdb;
$work = $mdb -> get( 'tasks_work', [ 'id', 'date_start' ], [
'AND' => [
'task_id' => $task_id,
'user_id' => $user_id,
'date_end' => null,
'deleted' => 0
],
'ORDER' => [ 'id' => 'DESC' ]
] );
if ( !$work or !isset( $work['id'] ) )
return [ 'status' => 'success' ];
$date_end_now = date( 'Y-m-d H:i:s' );
$is_too_short = self::is_work_duration_too_short( isset( $work['date_start'] ) ? $work['date_start'] : null, $date_end_now );
$mdb -> update( 'tasks_work', [
'date_end' => date( 'Y-m-d H:i:s' )
], [
'AND' => [
'task_id' => $task_id,
'user_id' => $user_id,
'date_end' => null
]
] );
'date_end' => $date_end_now,
'deleted' => $is_too_short ? 1 : 0
], [ 'id' => (int)$work['id'] ] );
return [ 'status' => 'success' ];
}
private static function is_work_duration_too_short( $date_start, $date_end )
{
$start_timestamp = strtotime( (string)$date_start );
$end_timestamp = strtotime( (string)$date_end );
if ( $start_timestamp === false or $end_timestamp === false )
return false;
return ( $end_timestamp - $start_timestamp ) < self::MIN_WORK_LOG_SECONDS;
}
static public function task_details( $task_id, $user_id = null )
{
global $mdb;
@@ -527,6 +570,9 @@ class Tasks
$children = $mdb -> get( 'tasks', 'id', [ 'parent_id' => $task_id ] );
$attachments_repository = new \Domain\Tasks\TaskAttachmentRepository( $mdb );
$attachments_repository -> purgeByTaskId( $task_id );
$mdb -> delete( 'tasks', [ 'id' => $task_id ] );
$mdb -> update( 'tasks', [ 'parent_id' => null ], [ 'parent_id' => $task_id ] );