mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-06-15 13:32:43 +01:00
Fixes after merge
This commit is contained in:
17
.env.ci
17
.env.ci
@@ -1,19 +1,22 @@
|
|||||||
APP_NAME=Laravel
|
APP_NAME=solidtime
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=http://localhost
|
APP_URL=http://localhost
|
||||||
|
APP_FORCE_HTTPS=false
|
||||||
|
SESSION_SECURE_COOKIE=false
|
||||||
|
|
||||||
LOG_CHANNEL=stack
|
LOG_CHANNEL=stack
|
||||||
LOG_DEPRECATIONS_CHANNEL=null
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
DB_CONNECTION=pgsql
|
DB_CONNECTION=pgsql_test
|
||||||
DB_HOST=127.0.0.1
|
|
||||||
DB_PORT=5432
|
DB_TEST_HOST=127.0.0.1
|
||||||
DB_DATABASE=laravel
|
DB_TEST_PORT=5432
|
||||||
DB_USERNAME=root
|
DB_TEST_DATABASE=laravel
|
||||||
DB_PASSWORD=root
|
DB_TEST_USERNAME=root
|
||||||
|
DB_TEST_PASSWORD=root
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ APP_KEY=base64:UNQNf1SXeASNkWux01Rj8EnHYx8FO0kAxWNDwktclkk=
|
|||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=https://solidtime.test
|
APP_URL=https://solidtime.test
|
||||||
APP_FORCE_HTTPS=true
|
APP_FORCE_HTTPS=true
|
||||||
|
SESSION_SECURE_COOKIE=true
|
||||||
|
|
||||||
SUPER_ADMINS=admin@example.com
|
SUPER_ADMINS=admin@example.com
|
||||||
|
|
||||||
@@ -12,12 +13,19 @@ LOG_DEPRECATIONS_CHANNEL=null
|
|||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
DB_CONNECTION=pgsql
|
DB_CONNECTION=pgsql
|
||||||
|
|
||||||
DB_HOST=pgsql
|
DB_HOST=pgsql
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_DATABASE=laravel
|
DB_DATABASE=laravel
|
||||||
DB_USERNAME=root
|
DB_USERNAME=root
|
||||||
DB_PASSWORD=root
|
DB_PASSWORD=root
|
||||||
|
|
||||||
|
DB_TEST_HOST=pgsql_test
|
||||||
|
DB_TEST_PORT=5432
|
||||||
|
DB_TEST_DATABASE=laravel
|
||||||
|
DB_TEST_USERNAME=root
|
||||||
|
DB_TEST_PASSWORD=root
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
FILESYSTEM_DISK=local
|
FILESYSTEM_DISK=local
|
||||||
|
|||||||
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@@ -5,7 +5,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
services:
|
services:
|
||||||
pgsql:
|
pgsql_test:
|
||||||
image: postgres:15
|
image: postgres:15
|
||||||
env:
|
env:
|
||||||
PGPASSWORD: 'root'
|
PGPASSWORD: 'root'
|
||||||
|
|||||||
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
services:
|
services:
|
||||||
mailpit:
|
mailpit:
|
||||||
image: 'axllent/mailpit:latest'
|
image: 'axllent/mailpit:latest'
|
||||||
pgsql:
|
pgsql_test:
|
||||||
image: postgres:15
|
image: postgres:15
|
||||||
env:
|
env:
|
||||||
PGPASSWORD: 'root'
|
PGPASSWORD: 'root'
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ class TimeEntryIndexRequest extends FormRequest
|
|||||||
],
|
],
|
||||||
// Filter only time entries that are active (have no end date, are still running)
|
// Filter only time entries that are active (have no end date, are still running)
|
||||||
'active' => [
|
'active' => [
|
||||||
'boolean',
|
'string',
|
||||||
|
'in:true,false',
|
||||||
],
|
],
|
||||||
// Limit the number of returned time entries
|
// Limit the number of returned time entries
|
||||||
'limit' => [
|
'limit' => [
|
||||||
|
|||||||
@@ -43,11 +43,15 @@ class ImportDatabaseHelper
|
|||||||
|
|
||||||
private int $createdCount;
|
private int $createdCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, array<int, string>>
|
||||||
|
*/
|
||||||
private array $validate;
|
private array $validate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param class-string<TModel> $model
|
* @param class-string<TModel> $model
|
||||||
* @param array<string> $identifiers
|
* @param array<string> $identifiers
|
||||||
|
* @param array<string, array<int, string>> $validate
|
||||||
*/
|
*/
|
||||||
public function __construct(string $model, array $identifiers, bool $attachToExisting = false, ?Closure $queryModifier = null, ?Closure $afterCreate = null, array $validate = [])
|
public function __construct(string $model, array $identifiers, bool $attachToExisting = false, ?Closure $queryModifier = null, ?Closure $afterCreate = null, array $validate = [])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -80,6 +80,21 @@ return [
|
|||||||
'sslmode' => 'prefer',
|
'sslmode' => 'prefer',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'pgsql_test' => [
|
||||||
|
'driver' => 'pgsql',
|
||||||
|
'url' => env('DATABASE_URL'),
|
||||||
|
'host' => env('DB_TEST_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_TEST_PORT', '5432'),
|
||||||
|
'database' => env('DB_TEST_DATABASE', 'forge'),
|
||||||
|
'username' => env('DB_TEST_USERNAME', 'forge'),
|
||||||
|
'password' => env('DB_TEST_PASSWORD', ''),
|
||||||
|
'charset' => 'utf8',
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'search_path' => 'public',
|
||||||
|
'sslmode' => 'prefer',
|
||||||
|
],
|
||||||
|
|
||||||
'sqlsrv' => [
|
'sqlsrv' => [
|
||||||
'driver' => 'sqlsrv',
|
'driver' => 'sqlsrv',
|
||||||
'url' => env('DATABASE_URL'),
|
'url' => env('DATABASE_URL'),
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace Database\Seeders;
|
|||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
|
use App\Models\Tag;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Models\TimeEntry;
|
use App\Models\TimeEntry;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@@ -109,6 +110,7 @@ class DatabaseSeeder extends Seeder
|
|||||||
{
|
{
|
||||||
DB::table((new TimeEntry())->getTable())->delete();
|
DB::table((new TimeEntry())->getTable())->delete();
|
||||||
DB::table((new Task())->getTable())->delete();
|
DB::table((new Task())->getTable())->delete();
|
||||||
|
DB::table((new Tag())->getTable())->delete();
|
||||||
DB::table((new Project())->getTable())->delete();
|
DB::table((new Project())->getTable())->delete();
|
||||||
DB::table((new Client())->getTable())->delete();
|
DB::table((new Client())->getTable())->delete();
|
||||||
DB::table((new User())->getTable())->delete();
|
DB::table((new User())->getTable())->delete();
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ const ClientResource = z
|
|||||||
})
|
})
|
||||||
.passthrough();
|
.passthrough();
|
||||||
const ClientCollection = z.array(ClientResource);
|
const ClientCollection = z.array(ClientResource);
|
||||||
|
const v1_import_import_Body = z
|
||||||
|
.object({ type: z.string(), data: z.string() })
|
||||||
|
.passthrough();
|
||||||
const OrganizationResource = z
|
const OrganizationResource = z
|
||||||
.object({ id: z.string(), name: z.string(), is_personal: z.string() })
|
.object({ id: z.string(), name: z.string(), is_personal: z.string() })
|
||||||
.passthrough();
|
.passthrough();
|
||||||
@@ -72,10 +75,21 @@ const updateTimeEntry_Body = z
|
|||||||
tags: z.union([z.array(z.string()), z.null()]).optional(),
|
tags: z.union([z.array(z.string()), z.null()]).optional(),
|
||||||
})
|
})
|
||||||
.passthrough();
|
.passthrough();
|
||||||
|
const UserResource = z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
email: z.string(),
|
||||||
|
role: z.string(),
|
||||||
|
is_placeholder: z.boolean(),
|
||||||
|
})
|
||||||
|
.passthrough();
|
||||||
|
const UserCollection = z.array(UserResource);
|
||||||
|
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
ClientResource,
|
ClientResource,
|
||||||
ClientCollection,
|
ClientCollection,
|
||||||
|
v1_import_import_Body,
|
||||||
OrganizationResource,
|
OrganizationResource,
|
||||||
ProjectResource,
|
ProjectResource,
|
||||||
ProjectCollection,
|
ProjectCollection,
|
||||||
@@ -87,6 +101,8 @@ export const schemas = {
|
|||||||
TimeEntryCollection,
|
TimeEntryCollection,
|
||||||
createTimeEntry_Body,
|
createTimeEntry_Body,
|
||||||
updateTimeEntry_Body,
|
updateTimeEntry_Body,
|
||||||
|
UserResource,
|
||||||
|
UserCollection,
|
||||||
};
|
};
|
||||||
|
|
||||||
const endpoints = makeApi([
|
const endpoints = makeApi([
|
||||||
@@ -306,6 +322,76 @@ const endpoints = makeApi([
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/v1/organizations/:organization/import',
|
||||||
|
alias: 'v1.import.import',
|
||||||
|
requestFormat: 'json',
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: 'body',
|
||||||
|
type: 'Body',
|
||||||
|
schema: v1_import_import_Body,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'organization',
|
||||||
|
type: 'Path',
|
||||||
|
schema: z.string().uuid(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
response: z
|
||||||
|
.object({
|
||||||
|
report: z
|
||||||
|
.object({
|
||||||
|
clients: z
|
||||||
|
.object({ created: z.number().int() })
|
||||||
|
.passthrough(),
|
||||||
|
projects: z
|
||||||
|
.object({ created: z.number().int() })
|
||||||
|
.passthrough(),
|
||||||
|
tasks: z
|
||||||
|
.object({ created: z.number().int() })
|
||||||
|
.passthrough(),
|
||||||
|
'time-entries': z
|
||||||
|
.object({ created: z.number().int() })
|
||||||
|
.passthrough(),
|
||||||
|
tags: z
|
||||||
|
.object({ created: z.number().int() })
|
||||||
|
.passthrough(),
|
||||||
|
users: z
|
||||||
|
.object({ created: z.number().int() })
|
||||||
|
.passthrough(),
|
||||||
|
})
|
||||||
|
.passthrough(),
|
||||||
|
})
|
||||||
|
.passthrough(),
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
status: 400,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 403,
|
||||||
|
description: `Authorization error`,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 404,
|
||||||
|
description: `Not found`,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 422,
|
||||||
|
description: `Validation error`,
|
||||||
|
schema: z
|
||||||
|
.object({
|
||||||
|
message: z.string(),
|
||||||
|
errors: z.record(z.array(z.string())),
|
||||||
|
})
|
||||||
|
.passthrough(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
method: 'get',
|
method: 'get',
|
||||||
path: '/v1/organizations/:organization/projects',
|
path: '/v1/organizations/:organization/projects',
|
||||||
@@ -664,7 +750,7 @@ const endpoints = makeApi([
|
|||||||
{
|
{
|
||||||
name: 'active',
|
name: 'active',
|
||||||
type: 'Query',
|
type: 'Query',
|
||||||
schema: z.string().optional(),
|
schema: z.enum(['true', 'false']).optional(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'limit',
|
name: 'limit',
|
||||||
@@ -824,6 +910,78 @@ const endpoints = makeApi([
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
path: '/v1/organizations/:organization/users',
|
||||||
|
alias: 'v1.users.index',
|
||||||
|
requestFormat: 'json',
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: 'organization',
|
||||||
|
type: 'Path',
|
||||||
|
schema: z.string().uuid(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
response: z.object({ data: UserCollection }).passthrough(),
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
status: 403,
|
||||||
|
description: `Authorization error`,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 404,
|
||||||
|
description: `Not found`,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 422,
|
||||||
|
description: `Validation error`,
|
||||||
|
schema: z
|
||||||
|
.object({
|
||||||
|
message: z.string(),
|
||||||
|
errors: z.record(z.array(z.string())),
|
||||||
|
})
|
||||||
|
.passthrough(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/v1/organizations/:organization/users/:user/invite-placeholder',
|
||||||
|
alias: 'v1.users.invite-placeholder',
|
||||||
|
requestFormat: 'json',
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: 'body',
|
||||||
|
type: 'Body',
|
||||||
|
schema: z.object({}).partial().passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'organization',
|
||||||
|
type: 'Path',
|
||||||
|
schema: z.string().uuid(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'user',
|
||||||
|
type: 'Path',
|
||||||
|
schema: z.string().uuid(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
response: z.string(),
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
status: 403,
|
||||||
|
description: `Authorization error`,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 404,
|
||||||
|
description: `Not found`,
|
||||||
|
schema: z.object({ message: z.string() }).passthrough(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const api = new Zodios('http://solidtime.test/api', endpoints);
|
export const api = new Zodios('http://solidtime.test/api', endpoints);
|
||||||
|
|||||||
@@ -21,8 +21,7 @@
|
|||||||
<env name="APP_ENV" value="testing"/>
|
<env name="APP_ENV" value="testing"/>
|
||||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||||
<env name="CACHE_DRIVER" value="array"/>
|
<env name="CACHE_DRIVER" value="array"/>
|
||||||
<env name="DB_CONNECTION" value="pgsql"/>
|
<env name="DB_CONNECTION" value="pgsql_test"/>
|
||||||
<env name="DB_HOST" value="pgsql_test"/>
|
|
||||||
<env name="MAIL_MAILER" value="array"/>
|
<env name="MAIL_MAILER" value="array"/>
|
||||||
<env name="PULSE_ENABLED" value="false"/>
|
<env name="PULSE_ENABLED" value="false"/>
|
||||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default defineConfig({
|
|||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: process.env.CI ? 'list' : 'html',
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class TimeEntryEndpointTest extends ApiEndpointTestAbstract
|
|||||||
// Act
|
// Act
|
||||||
$response = $this->getJson(route('api.v1.time-entries.index', [
|
$response = $this->getJson(route('api.v1.time-entries.index', [
|
||||||
$data->organization->getKey(),
|
$data->organization->getKey(),
|
||||||
'active' => true,
|
'active' => 'true',
|
||||||
'user_id' => $data->user->getKey(),
|
'user_id' => $data->user->getKey(),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user