diff --git a/.gitignore b/.gitignore index 7d797cc..0d5bf7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /vendor/ -/data/ +data/cache +data/upload /ts.db /config.*.ini /www/ diff --git a/README.md b/README.md index ef634ed..1181c40 100644 --- a/README.md +++ b/README.md @@ -6,34 +6,3 @@ We make releasing music easier. We are DIY artists, label people, software developers and music consumers who are building tools to give indies superpowers in the age of big data. "Giving indies superpowers in the age of big data." - -Dev todo --------- - -Notes for Wednesday: the database speedup is immense. From 6 minutes to about 15 seconds. -But there's still more to do, and ideally it should all be done within 1 second. -So, here's how: - -- [x] When the file is uploaded, just store it in the Upload table. -- [x] Introduce a new field, Upload.processedUsages -- [x] In a background script, loop over all uploads that are not processed and extract their usages (then mark as processed) -- [ ] Introduce another new field, Usage.processed -- [ ] In another background script, loop over all usages that are unprocessed, finishing the job here. -- [ ] The usage processor needs to match products and artists - rather than doing this individually in a loop, lookup the unique artist/product first, to cache the IDs (or create new ones), then it's possible to insert UsageOfProduct rows on bulk! -- [ ] Then optimise further with a profiler. Ideally, a very large import should be completed before the page has chance to reload. -- [ ] If a spinner is necessary, it should be put onto the three-checkbox page. It's also possible to know how many usages are left to process, so an ACTUAL progress bar is possible. - -Setup guide ------------ - -TODO: From scratch for Linux, Windows and Mac. - -Running locally ---------------- - -TODO. - -Writing/running tests ---------------------- - -TODO. diff --git a/asset/.DS_Store b/asset/.DS_Store index 41d07b4..6d638cd 100644 Binary files a/asset/.DS_Store and b/asset/.DS_Store differ diff --git a/behat.yml b/behat.yml index 17717b5..3479a82 100644 --- a/behat.yml +++ b/behat.yml @@ -14,7 +14,8 @@ default: - \SHIFT\Trackshift\BehatContext\AuthContext: - \SHIFT\Trackshift\BehatContext\PageContext: - \SHIFT\Trackshift\BehatContext\UploadContext: - - \SHIFT\Trackshift\BehatContext\AnotherContext: + - \SHIFT\Trackshift\BehatContext\NotificationContext: + - \SHIFT\Trackshift\BehatContext\DebugContext: extensions: Behat\MinkExtension: diff --git a/class/Audit/AuditItem.php b/class/Audit/AuditItem.php index 5b99956..f739b89 100644 --- a/class/Audit/AuditItem.php +++ b/class/Audit/AuditItem.php @@ -31,7 +31,8 @@ public function getHtml():string { "create" => "Created new $typeName ($descriptionOrId)", "update" => "Updated $typeName ($descriptionOrId)", "delete" => "Deleted $typeName ($descriptionOrId)", - default => "Something happened...", + "notification" => $descriptionOrId, + default => "Unhandled audit type ($this->type)", }; } diff --git a/class/Audit/AuditRepository.php b/class/Audit/AuditRepository.php index d9fecdc..5723d42 100644 --- a/class/Audit/AuditRepository.php +++ b/class/Audit/AuditRepository.php @@ -1,12 +1,22 @@ db->insert("insertCreation", [ "id" => new Ulid("audit"), @@ -16,6 +26,16 @@ public function create(User $user, string $newId, ?string $description = null):v ]); } + public function notify(User $user, string $description, ?string $idInQuestion = null):void { + $this->db->insert("insertNotification", [ + "id" => new Ulid("audit"), + "userId" => $user->id, + "description" => $description, + "valueId" => $idInQuestion, + ]); + } + + public function delete(User $user, string $deletedId, ?string $description = null):void { $this->db->insert("insertDeletion", [ "id" => new Ulid("audit"), @@ -39,11 +59,25 @@ public function getAll(User $user):array { return $auditItemArray; } + public function getLatest(User $user, bool $notificationOnly = false):null|AuditItem|NotificationItem { + if($notificationOnly) { + $row = $this->db->fetch("getLatestNotification", $user->id); + } + else { + $row = $this->db->fetch("getLatest", $user->id); + } + return $this->rowToAuditItem($row, $user); + } + private function rowToAuditItem(?Row $row, ?User $user = null):?AuditItem { if(!$row) { return null; } + if(!$user) { + $user = $this->userRepository->getById($row->getString("userId")); + } + return new AuditItem( $row->getString("id"), $user, @@ -85,6 +119,22 @@ public function update( } } + public function checkNotifications(User $user):void { + $this->userRepository->setNotificationCheckTime($user); + } + + public function isNewNotification(User $user):bool { + $timeLatestNotification = null; + $timeLastChecked = $this->userRepository->getLatestNotificationCheckTime($user); + + if($latestNotification = $this->getLatest($user, true)) { + $timeLatestNotification = new DateTime(); + $timeLatestNotification->setTimestamp((new Ulid(init: $latestNotification->id))->getTimestamp() / 1000); + } + + return $timeLatestNotification && $timeLatestNotification > $timeLastChecked; + } + /** @return array key = property name, value = "$oldValue -> $newValue" */ private function getDiff(object $from, object $to):array { $fromVars = get_object_vars($from); @@ -102,4 +152,5 @@ private function getDiff(object $from, object $to):array { } + } diff --git a/class/Auth/UserRepository.php b/class/Auth/UserRepository.php index 01ecb84..95be832 100644 --- a/class/Auth/UserRepository.php +++ b/class/Auth/UserRepository.php @@ -1,7 +1,10 @@ session->getInstance(self::SESSION_USER, User::class); } + public function getById(string $id):?User { + $row = $this->db->fetch("getById", $id); + return $this->rowToUser($row); + } + public function createNewUser():User { $user = new User(new Ulid("user")); $this->db->insert("create", $user->id); @@ -30,4 +38,30 @@ public function createNewUser():User { public function persistUser(User $user):void { $this->session->set(self::SESSION_USER, $user); } + + public function setNotificationCheckTime(User $user, DateTime $when = null):void { + if(is_null($when)) { + $when = new DateTime(); + } + + $this->db->update("setNotificationCheckedAt", [ + "userId" => $user->id, + "checkedAt" => $when->getTimestamp(), + ]); + } + + public function getLatestNotificationCheckTime(User $user):?DateTimeInterface { + return $this->db->fetchDateTime("getLastNotificationCheckTime", $user->id); + } + + private function rowToUser(?Row $row):?User { + if(!$row) { + return null; + } + + return new User($row->getString("id")); + } + + + } diff --git a/class/Cost/CostRepository.php b/class/Cost/CostRepository.php index 302d853..4aacdd3 100644 --- a/class/Cost/CostRepository.php +++ b/class/Cost/CostRepository.php @@ -28,6 +28,7 @@ public function create(Cost $cost, User $user):void { $this->db->insert("create", [ "id" => $cost->id, "productId" => $cost->product->id, + "userId" => $user->id, "description" => $cost->description, "amount" => $cost->amount->value, ]); diff --git a/class/ServiceLoader.php b/class/ServiceLoader.php index e85822b..58fb726 100644 --- a/class/ServiceLoader.php +++ b/class/ServiceLoader.php @@ -12,6 +12,7 @@ use SHIFT\Trackshift\Content\ContentRepository; use SHIFT\Trackshift\Cost\CostRepository; use SHIFT\Trackshift\Product\ProductRepository; +use SHIFT\Trackshift\Split\SplitRepository; use SHIFT\Trackshift\Upload\UploadManager; class ServiceLoader extends DefaultServiceLoader { @@ -19,6 +20,7 @@ public function loadAuditRepo():AuditRepository { $database = $this->container->get(Database::class); return new AuditRepository( $database->queryCollection("Audit"), + $this->container->get(UserRepository::class), ); } @@ -89,4 +91,11 @@ public function loadCostRepository():CostRepository { $this->container->get(AuditRepository::class), ); } + + public function loadSplitRepository():SplitRepository { + $database = $this->container->get(Database::class); + return new SplitRepository( + $database->queryCollection("Split"), + ); + } } diff --git a/class/Split/EmptySplitPercentage.php b/class/Split/EmptySplitPercentage.php new file mode 100644 index 0000000..6349287 --- /dev/null +++ b/class/Split/EmptySplitPercentage.php @@ -0,0 +1,9 @@ + */ + public function getPercentageList(User $user, string $productId):array { + return []; + } + +} diff --git a/class/Upload/UnknownUpload.php b/class/Upload/UnknownUpload.php index f921b3e..0b237cf 100644 --- a/class/Upload/UnknownUpload.php +++ b/class/Upload/UnknownUpload.php @@ -8,12 +8,12 @@ protected function processUsages():void {} // phpcs:ignore public function extractArtistName(array $row):string { - return ""; + return "Unknown"; } // phpcs:ignore public function extractProductTitle(array $row):string { - return ""; + return "Unknown"; } // phpcs:ignore diff --git a/class/Upload/UploadManager.php b/class/Upload/UploadManager.php index b11af09..e33d8b5 100644 --- a/class/Upload/UploadManager.php +++ b/class/Upload/UploadManager.php @@ -22,9 +22,7 @@ use SHIFT\Trackshift\Usage\Usage; use SplFileObject; -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ +/** @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ readonly class UploadManager extends Repository { public function __construct( QueryCollection $db, @@ -67,7 +65,13 @@ public function upload(User $user, FileUpload...$uploadList):array { "type" => $upload::class, ]); - $this->auditRepository->create($user, $upload->id, $upload->filename); + if($upload instanceof UnknownUpload) { + $this->auditRepository->notify($user, "Your latest upload was not processed ($upload->filename)", $upload->id); + } + else { + $this->auditRepository->create($user, $upload->id, $upload->filename); + } + array_push($completedUploadList, $upload); } @@ -405,6 +409,4 @@ private function rowToProduct(?Row $row, ?Artist $artist):?Product { $artist // ?? $this->getArtistById($row->getString("artistId") ); } - - } diff --git a/composer.json b/composer.json index 4f341e0..43e1cdf 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "php": ">=8.2", "superhyperinstantfuturetime/spotify-api": "dev-master", "phpgt/webengine": "dev-master", - "phpgt/database": "dev-dynamic-sets as v1.5.0", + "phpgt/database": "dev-318-semicolon as v1.4.0", "league/commonmark": "^2.4" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 27040bd..c9871e1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fb4cd5a2e3aaed7361c37b8f1d257cfb", + "content-hash": "0ca323d77187aab6d407099eaa037543", "packages": [ { "name": "composer/semver", @@ -226,6 +226,66 @@ ], "time": "2020-10-13T00:52:37+00:00" }, + { + "name": "greenlion/php-sql-parser", + "version": "v4.6.0", + "source": { + "type": "git", + "url": "https://github.com/greenlion/PHP-SQL-Parser.git", + "reference": "f0e4645eb1612f0a295e3d35bda4c7740ae8c366" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/greenlion/PHP-SQL-Parser/zipball/f0e4645eb1612f0a295e3d35bda4c7740ae8c366", + "reference": "f0e4645eb1612f0a295e3d35bda4c7740ae8c366", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "analog/analog": "^1.0.6", + "phpunit/phpunit": "^9.5.13", + "squizlabs/php_codesniffer": "^1.5.1" + }, + "type": "library", + "autoload": { + "psr-0": { + "PHPSQLParser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Justin Swanhart", + "email": "greenlion@gmail.com", + "homepage": "http://code.google.com/u/greenlion@gmail.com/", + "role": "Owner" + }, + { + "name": "André Rothe", + "email": "phosco@gmx.de", + "homepage": "https://www.phosco.info", + "role": "Committer" + } + ], + "description": "A pure PHP SQL (non validating) parser w/ focus on MySQL dialect of SQL", + "homepage": "https://github.com/greenlion/PHP-SQL-Parser", + "keywords": [ + "creator", + "mysql", + "parser", + "sql" + ], + "support": { + "issues": "https://github.com/greenlion/PHP-SQL-Parser/issues", + "source": "https://github.com/greenlion/PHP-SQL-Parser" + }, + "time": "2023-03-09T20:54:23+00:00" + }, { "name": "league/commonmark", "version": "2.4.1", @@ -467,16 +527,16 @@ }, { "name": "nette/schema", - "version": "v1.2.4", + "version": "v1.2.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab" + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab", - "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab", + "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", "shasum": "" }, "require": { @@ -523,9 +583,9 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.2.4" + "source": "https://github.com/nette/schema/tree/v1.2.5" }, - "time": "2023-08-05T18:56:25+00:00" + "time": "2023-10-05T20:37:59+00:00" }, { "name": "nette/utils", @@ -1089,20 +1149,21 @@ }, { "name": "phpgt/database", - "version": "dev-dynamic-sets", + "version": "dev-318-semicolon", "source": { "type": "git", "url": "https://github.com/PhpGt/Database.git", - "reference": "4e48d3d390d0a54be969636535dfaa1e1def82b5" + "reference": "8ab44c9a8193bc258ecc6c8ec921b33a78945ac7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PhpGt/Database/zipball/4e48d3d390d0a54be969636535dfaa1e1def82b5", - "reference": "4e48d3d390d0a54be969636535dfaa1e1def82b5", + "url": "https://api.github.com/repos/PhpGt/Database/zipball/8ab44c9a8193bc258ecc6c8ec921b33a78945ac7", + "reference": "8ab44c9a8193bc258ecc6c8ec921b33a78945ac7", "shasum": "" }, "require": { "ext-pdo": "*", + "greenlion/php-sql-parser": "^4.6", "php": ">=8.1", "phpgt/cli": "^1.3", "phpgt/config": "^v1.1.0" @@ -1144,7 +1205,7 @@ "description": "Database API organisation.", "support": { "issues": "https://github.com/PhpGt/Database/issues", - "source": "https://github.com/PhpGt/Database/tree/dynamic-sets" + "source": "https://github.com/PhpGt/Database/tree/318-semicolon" }, "funding": [ { @@ -1152,7 +1213,7 @@ "type": "github" } ], - "time": "2023-08-18T11:21:10+00:00" + "time": "2023-10-11T23:23:50+00:00" }, { "name": "phpgt/dataobject", @@ -3353,16 +3414,16 @@ }, { "name": "composer/pcre", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", "shasum": "" }, "require": { @@ -3404,7 +3465,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.0" + "source": "https://github.com/composer/pcre/tree/3.1.1" }, "funding": [ { @@ -3420,7 +3481,7 @@ "type": "tidelift" } ], - "time": "2022-11-17T09:50:14+00:00" + "time": "2023-10-11T07:11:09+00:00" }, { "name": "composer/xdebug-handler", @@ -3547,16 +3608,16 @@ }, { "name": "friends-of-behat/mink-extension", - "version": "v2.7.3", + "version": "v2.7.4", "source": { "type": "git", "url": "https://github.com/FriendsOfBehat/MinkExtension.git", - "reference": "b1ccaef9136f62c8efaad88b966345dd68374fa9" + "reference": "18d5a53dff3e2c8934c53e2db8b02b7ea345fe85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfBehat/MinkExtension/zipball/b1ccaef9136f62c8efaad88b966345dd68374fa9", - "reference": "b1ccaef9136f62c8efaad88b966345dd68374fa9", + "url": "https://api.github.com/repos/FriendsOfBehat/MinkExtension/zipball/18d5a53dff3e2c8934c53e2db8b02b7ea345fe85", + "reference": "18d5a53dff3e2c8934c53e2db8b02b7ea345fe85", "shasum": "" }, "require": { @@ -3606,9 +3667,9 @@ "web" ], "support": { - "source": "https://github.com/FriendsOfBehat/MinkExtension/tree/v2.7.3" + "source": "https://github.com/FriendsOfBehat/MinkExtension/tree/v2.7.4" }, - "time": "2023-09-12T09:50:10+00:00" + "time": "2023-10-03T13:15:12+00:00" }, { "name": "masterminds/html5", @@ -3798,12 +3859,12 @@ "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "8b513efa2390024ebc487d0feeea17b4b78fc186" + "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/8b513efa2390024ebc487d0feeea17b4b78fc186", - "reference": "8b513efa2390024ebc487d0feeea17b4b78fc186", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/d12f25bcdfb7754bea458a4a5cb159d55e9950d0", + "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0", "shasum": "" }, "require": { @@ -3846,7 +3907,7 @@ ], "support": { "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/master" + "source": "https://github.com/pdepend/pdepend/tree/2.15.1" }, "funding": [ { @@ -3854,7 +3915,7 @@ "type": "tidelift" } ], - "time": "2023-09-07T10:27:45+00:00" + "time": "2023-09-28T12:00:56+00:00" }, { "name": "phar-io/manifest", @@ -3969,22 +4030,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.13.0", + "version": "2.14.1", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "dad0228156856b3ad959992f9748514fa943f3e3" + "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/dad0228156856b3ad959992f9748514fa943f3e3", - "reference": "dad0228156856b3ad959992f9748514fa943f3e3", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/442fc2c34edcd5198b442d8647c7f0aec3afabe8", + "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", "ext-xml": "*", - "pdepend/pdepend": "^2.12.1", + "pdepend/pdepend": "^2.15.1", "php": ">=5.3.9" }, "require-dev": { @@ -3994,7 +4055,7 @@ "gregwar/rst": "^1.0", "mikey179/vfsstream": "^1.6.8", "phpunit/phpunit": "^4.8.36 || ^5.7.27", - "squizlabs/php_codesniffer": "^2.0" + "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" }, "bin": [ "src/bin/phpmd" @@ -4031,6 +4092,7 @@ "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", "homepage": "https://phpmd.org/", "keywords": [ + "dev", "mess detection", "mess detector", "pdepend", @@ -4040,7 +4102,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.13.0" + "source": "https://github.com/phpmd/phpmd/tree/2.14.1" }, "funding": [ { @@ -4048,20 +4110,20 @@ "type": "tidelift" } ], - "time": "2022-09-10T08:44:15+00:00" + "time": "2023-09-28T13:07:44+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.35", + "version": "1.10.38", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3" + "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e730e5facb75ffe09dfb229795e8c01a459f26c3", - "reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691", + "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691", "shasum": "" }, "require": { @@ -4110,20 +4172,20 @@ "type": "tidelift" } ], - "time": "2023-09-19T15:27:56+00:00" + "time": "2023-10-06T14:19:14+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.6", + "version": "10.1.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "56f33548fe522c8d82da7ff3824b42829d324364" + "reference": "355324ca4980b8916c18b9db29f3ef484078f26e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/56f33548fe522c8d82da7ff3824b42829d324364", - "reference": "56f33548fe522c8d82da7ff3824b42829d324364", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e", + "reference": "355324ca4980b8916c18b9db29f3ef484078f26e", "shasum": "" }, "require": { @@ -4180,7 +4242,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7" }, "funding": [ { @@ -4188,7 +4250,7 @@ "type": "github" } ], - "time": "2023-09-19T04:59:03+00:00" + "time": "2023-10-04T15:34:17+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4435,16 +4497,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.3.5", + "version": "10.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503" + "reference": "62bd7af13d282deeb95650077d28ba3600ca321c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503", - "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/62bd7af13d282deeb95650077d28ba3600ca321c", + "reference": "62bd7af13d282deeb95650077d28ba3600ca321c", "shasum": "" }, "require": { @@ -4484,7 +4546,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.3-dev" + "dev-main": "10.4-dev" } }, "autoload": { @@ -4516,7 +4578,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.1" }, "funding": [ { @@ -4532,7 +4594,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:42:37+00:00" + "time": "2023-10-08T05:01:11+00:00" }, { "name": "psr/log", @@ -4830,16 +4892,16 @@ }, { "name": "sebastian/complexity", - "version": "3.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "c70b73893e10757af9c6a48929fa6a333b56a97a" + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a", - "reference": "c70b73893e10757af9c6a48929fa6a333b56a97a", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", "shasum": "" }, "require": { @@ -4852,7 +4914,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" } }, "autoload": { @@ -4876,7 +4938,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" }, "funding": [ { @@ -4884,7 +4946,7 @@ "type": "github" } ], - "time": "2023-08-31T09:55:53+00:00" + "time": "2023-09-28T11:50:59+00:00" }, { "name": "sebastian/diff", @@ -5019,16 +5081,16 @@ }, { "name": "sebastian/exporter", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344" + "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c3fa8483f9539b190f7cd4bfc4a07631dd1df344", - "reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc", + "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc", "shasum": "" }, "require": { @@ -5042,7 +5104,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -5085,7 +5147,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1" }, "funding": [ { @@ -5093,7 +5155,7 @@ "type": "github" } ], - "time": "2023-09-18T07:15:37+00:00" + "time": "2023-09-24T13:22:09+00:00" }, { "name": "sebastian/global-state", @@ -5856,16 +5918,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v6.3.4", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "68a5a9570806a087982f383f6109c5e925892a49" + "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/68a5a9570806a087982f383f6109c5e925892a49", - "reference": "68a5a9570806a087982f383f6109c5e925892a49", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2ed62b3bf98346e1f45529a7b6be2196739bb993", + "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993", "shasum": "" }, "require": { @@ -5917,7 +5979,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.3.4" + "source": "https://github.com/symfony/dependency-injection/tree/v6.3.5" }, "funding": [ { @@ -5933,7 +5995,7 @@ "type": "tidelift" } ], - "time": "2023-08-16T17:55:17+00:00" + "time": "2023-09-25T16:46:40+00:00" }, { "name": "symfony/dom-crawler", @@ -6223,16 +6285,16 @@ }, { "name": "symfony/http-client", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00" + "reference": "213e564da4cbf61acc9728d97e666bcdb868c10d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00", - "reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00", + "url": "https://api.github.com/repos/symfony/http-client/zipball/213e564da4cbf61acc9728d97e666bcdb868c10d", + "reference": "213e564da4cbf61acc9728d97e666bcdb868c10d", "shasum": "" }, "require": { @@ -6295,7 +6357,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.3.2" + "source": "https://github.com/symfony/http-client/tree/v6.3.5" }, "funding": [ { @@ -6311,7 +6373,7 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2023-09-29T15:57:12+00:00" }, { "name": "symfony/http-client-contracts", @@ -6393,16 +6455,16 @@ }, { "name": "symfony/mime", - "version": "v6.3.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98" + "reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/9a0cbd52baa5ba5a5b1f0cacc59466f194730f98", - "reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98", + "url": "https://api.github.com/repos/symfony/mime/zipball/d5179eedf1cb2946dbd760475ebf05c251ef6a6e", + "reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e", "shasum": "" }, "require": { @@ -6457,7 +6519,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.3.3" + "source": "https://github.com/symfony/mime/tree/v6.3.5" }, "funding": [ { @@ -6473,7 +6535,7 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2023-09-29T06:59:36+00:00" }, { "name": "symfony/polyfill-ctype", @@ -7052,16 +7114,16 @@ }, { "name": "symfony/string", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "53d1a83225002635bca3482fcbf963001313fb68" + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", - "reference": "53d1a83225002635bca3482fcbf963001313fb68", + "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339", + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339", "shasum": "" }, "require": { @@ -7118,7 +7180,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.2" + "source": "https://github.com/symfony/string/tree/v6.3.5" }, "funding": [ { @@ -7134,7 +7196,7 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2023-09-18T10:38:32+00:00" }, { "name": "symfony/translation", @@ -7509,9 +7571,9 @@ "aliases": [ { "package": "phpgt/database", - "version": "dev-dynamic-sets", - "alias": "v1.5.0", - "alias_normalized": "1.5.0.0" + "version": "dev-318-semicolon", + "alias": "v1.4.0", + "alias_normalized": "1.4.0.0" } ], "minimum-stability": "stable", diff --git a/data/web-content/upload-fail.md b/data/web-content/upload-fail.md new file mode 100644 index 0000000..8a51f75 --- /dev/null +++ b/data/web-content/upload-fail.md @@ -0,0 +1,20 @@ +# Why did your upload fail? + +
+ +### We're still building TrackShift, and learning all the time about the different formats that sales reports come in. + +### The reason your upload failed is probably one of these... + +_- We haven't seen one like it before, so TrackShift doesn't know what it is._ + +If this is the case, we're happy because we can easily teach TrackShift to process a new type of upload. + +_- It's got something in it that causes processing to fail._ + +Again, we can teach TrackShift what to do if this is what's happening. + +_- It's not a file type that we support._ + +Currently, TrackShift is built to handle sales report files. These normally come in .csv format. TrackShift can't process PDFs, JPGs or anything like that. We'd love to talk to you about what files you have though, so [get in touch](mailto:biff@trackshift.app). +
diff --git a/page/_common.php b/page/_common.php index 441b832..4264d03 100644 --- a/page/_common.php +++ b/page/_common.php @@ -3,7 +3,9 @@ use Gt\Dom\Element; use Gt\Dom\HTMLDocument; use Gt\DomTemplate\DocumentBinder; +use SHIFT\Trackshift\Audit\AuditRepository; use SHIFT\Trackshift\Auth\User; +use SHIFT\Trackshift\Auth\UserRepository; use SHIFT\Trackshift\Content\ContentRepository; use SHIFT\Trackshift\Egg\UploadMessageList; use SHIFT\Trackshift\Upload\UploadManager; @@ -30,3 +32,9 @@ function go( $binder->bindList(new UploadMessageList(3), $fileUploader); } } + +function go_after(?User $user, AuditRepository $auditRepository, HTMLDocument $document):void { + if($user && $auditRepository->isNewNotification($user)) { + $document->querySelector("global-header .bell")->classList->add("notify"); + } +} diff --git a/page/_component/account-tabs.html b/page/_component/account-tabs.html index bf3d3af..3ccda0c 100644 --- a/page/_component/account-tabs.html +++ b/page/_component/account-tabs.html @@ -8,4 +8,7 @@
  • Costs
  • +
  • + Splits +
  • diff --git a/page/_component/audit-list.html b/page/_component/audit-list.html index 07496b1..d9a6bd4 100644 --- a/page/_component/audit-list.html +++ b/page/_component/audit-list.html @@ -1,5 +1,5 @@