Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
5803aff
fix: upgrade goteo/benzina to 0.6
subiabre Jul 30, 2026
995eef6
feat: increase Nominatim cache TTL
subiabre Aug 10, 2026
3b3fa99
fix: allow long addresses for territory data
subiabre Aug 12, 2026
72a04d4
fix: build project addresses from goteo 3 territory fields
subiabre Aug 12, 2026
c6dad06
fix: handle empty strings for video sources
subiabre Aug 13, 2026
79ef243
fix: update project drafts deadline to 2026
subiabre Aug 13, 2026
c0fab8a
feat: split project description into 4 fields
subiabre Aug 13, 2026
d0e4895
feat: bump doctrine related dependencies
subiabre Aug 13, 2026
e953837
feat: bump symfony related dependencies
subiabre Aug 13, 2026
3d800b6
feat: make categories work on idOrSlug
subiabre Aug 13, 2026
e3ef9ea
fix: allow filtering on project descBrief property
subiabre Aug 14, 2026
c1d05ce
fix: update constraints on project update to allow optional updates o…
subiabre Aug 14, 2026
e9bb6aa
fix: update Projects test suite to new project shape
subiabre Aug 14, 2026
8b93dc6
Merge pull request #232 from goteo/feat/bump-benzina
subiabre Aug 14, 2026
4f8b0a1
fix: order of DROP operations in migration Version20260813171902
subiabre Aug 14, 2026
111e4ce
Merge pull request #233 from goteo/hotfix/doctrine-migration-order
subiabre Aug 14, 2026
799112a
fix: move accounting balance and checkout to supports listeners to on…
subiabre Aug 14, 2026
5bd4040
Merge pull request #234 from goteo/fix/update-checkout-listeners-to-o…
subiabre Aug 17, 2026
4e60b98
fix: bad order of filter safeguards
subiabre Aug 17, 2026
e1c9b29
chore: code style by php-cs-fixer
subiabre Aug 17, 2026
492a211
fix: prevent uninitialized fields on api resource from breaking Accou…
subiabre Aug 17, 2026
4b7648d
fix: small bug preventing code improvements on Accounting api resource
subiabre Aug 17, 2026
294c447
Merge pull request #235 from goteo/hotfix/bad-order-of-filter-safeguards
subiabre Aug 17, 2026
8b7f480
feat: add cover property on ProjectReward resource
subiabre Aug 18, 2026
5965f65
feat: add cover property to Project resources
subiabre Aug 18, 2026
ee61072
feat: use video cover for project cover
subiabre Aug 18, 2026
7a6a262
feat: add migration for property cover on project and rewards
subiabre Aug 18, 2026
80ac968
fix: small improvements on UserOwned helpers
subiabre Aug 18, 2026
28e0999
Merge pull request #236 from goteo/feat/cover-images
subiabre Aug 18, 2026
6d23891
feat: add territory to project creation
subiabre Aug 25, 2026
87f6670
Merge pull request #237 from goteo/feat/post-project-with-territory
subiabre Aug 25, 2026
31af0cb
feat: mark creation fields as required
subiabre Aug 25, 2026
9633cb5
Merge pull request #238 from goteo/feat/post-project-with-territory
subiabre Aug 25, 2026
5c54d1b
feat: add CollaborationCandidacy resource
subiabre Aug 26, 2026
4d4de0f
fix: update old validations access of new types
subiabre Aug 26, 2026
40ff4b5
feat: add validation for charges targetting projects not in campaign
subiabre Aug 26, 2026
28c27ad
feat: validate new collaboration candicacies are to open collaborations
subiabre Aug 26, 2026
0a887e8
feat: prevent future object access issues in SameProjectRewardChargeV…
subiabre Aug 26, 2026
5527097
Merge pull request #239 from goteo/feat/project-collaborations-apply
subiabre Aug 26, 2026
a48fd6d
fix: return void on succesfull delete operations
subiabre Sep 3, 2026
7b08eca
Merge pull request #240 from goteo/fix/bad-return-in-delete-operations
subiabre Sep 3, 2026
4d4e7a7
fix: force set of isFinite property
subiabre Sep 3, 2026
a785eaf
Merge pull request #241 from goteo/fix/rewards-not-being-set-to-infinite
subiabre Sep 3, 2026
1bc9797
feat: allow to filter ProjectBudgetItem by type and deadline
subiabre Sep 8, 2026
0f3b7f9
Merge pull request #242 from goteo/feat/budget-items-missing-filters
subiabre Sep 8, 2026
5e96bc9
feat: remove example values from .env
subiabre Sep 10, 2026
565d012
feat: add testing encryption keys
subiabre Sep 11, 2026
8ad3e79
feat: make project in BudgetItem body required
subiabre Sep 11, 2026
6247fd2
feat: add testing encryption keys to actions
subiabre Sep 11, 2026
7708e39
Merge pull request #243 from goteo/fix/update-example-env-values
subiabre Sep 11, 2026
85aac10
feat: add collaborations property to ProjectApiResource
subiabre Sep 17, 2026
28a6706
Merge pull request #244 from goteo/feat/add-collaborations-to-projects
subiabre Sep 17, 2026
9b5b5a9
feat: Update Users PATCH body (#246)
subiabre Sep 23, 2026
6de849e
Merge branch 'main' into develop
subiabre Sep 24, 2026
6973e9a
fix: make app:oauth2-server:consent-client true by default
subiabre Sep 25, 2026
6b9014d
feat: bump league/oauth2-server-bundle to 1.2.2
subiabre Sep 25, 2026
03ff6f7
feat: add UserConverter decorator to have league/oauth2-server JWT's …
subiabre Sep 25, 2026
b5e03e2
fix: specify OAuth2 and separate server from client utilities
subiabre Sep 25, 2026
1699a43
fix: make app_user_provider use ID instead of handle
subiabre Sep 25, 2026
ee369bc
Merge pull request #248 from goteo/fix/update-jwt-subject
subiabre Sep 25, 2026
b0bc61f
feat: add explaining comment to doctrine_encryption.key_id
subiabre Sep 29, 2026
8743c79
feat: add status to reward claims
subiabre Sep 29, 2026
412cf4d
feat: make default RewardClaim entity status in_pending
subiabre Sep 29, 2026
4fedf26
feat: add shorter check for ownership of projects
subiabre Sep 29, 2026
bb297c5
feat: allow to modify status of reward claims
subiabre Sep 29, 2026
81a264a
feat: add shipping address to reward claims
subiabre Sep 29, 2026
738f2ad
fix: remove requirement of status in claim update op
subiabre Sep 29, 2026
242755e
fix: update filters and remove obsolete attributes from ProjectReward…
subiabre Sep 29, 2026
6f88f74
feat: update DB layer for project reward claims
subiabre Sep 29, 2026
995fd33
fix: code style issues by PHP-CS-Fixer
subiabre Sep 29, 2026
a328073
feat: add DoctrineLoggablePumpTrait to remove Gedmo Loggable event li…
subiabre Sep 30, 2026
80178bb
fix: update legacy ref to FileUriException
subiabre Sep 30, 2026
1f6eb4f
feat: pump reward claim status and shipping address from v3 records
subiabre Sep 30, 2026
9b8911e
fix: update pumps batch sizes and injected dependencies
subiabre Sep 30, 2026
dd5361c
Merge pull request #250 from goteo/feat/update-project-rewardclaim-data
subiabre Sep 30, 2026
74db679
feat: pump user roles
subiabre Sep 30, 2026
87ccc07
feat: add true image cover retrieval and leave video as fallback for …
subiabre Sep 30, 2026
10c7806
feat: pump project collaborations
subiabre Sep 30, 2026
574b6d3
feat: allow cascading of collaborations
subiabre Sep 30, 2026
1bcb1f3
fix: set isFulfilled of collaboration
subiabre Sep 30, 2026
e1e1604
fix: link collaboration to in-pumping project
subiabre Sep 30, 2026
727ddae
fix: add trailing comma to list of fulfilling statuses
subiabre Sep 30, 2026
3d0925c
test: update PHPUnit CI to use bin/phpunit instead of action
subiabre Sep 30, 2026
deef8ad
feat: set memory_limit of PHPUnit run on CI to 128M
subiabre Sep 30, 2026
a237124
Merge pull request #251 from goteo/feat/pump-user-roles
subiabre Sep 30, 2026
c3b4299
fix: add user avatar to user pump processing
subiabre Sep 30, 2026
7732352
fix: set invests batch size to 1 to avoid support duplicates on insert
subiabre Sep 30, 2026
07b0b47
Merge pull request #252 from goteo/fix/missing-user-avatar-pumping
subiabre Sep 30, 2026
5d878f2
Merge pull request #253 from goteo/fix/pumping-bugs
subiabre Oct 1, 2026
2dec0d1
fix: HTTP (!s) scheme in callback for OAuth2 providers (#254)
subiabre Oct 2, 2026
86ba2c4
fix: HTTPS in OAuth2 redirect_uri (#255)
subiabre Oct 5, 2026
14ee28b
[feat] Project reviews (#177)
subiabre Oct 7, 2026
ac47aec
feat: Themes (#257)
subiabre Oct 8, 2026
dc23606
Merge branch 'main' into develop
subiabre Oct 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
APP_ENV=dev
APP_SECRET=b8ec44a08e5f4ba917879713a4a8e63c
APP_LOCALE='es'
# DO NOT LEAVE OPEN UNLESS YOU'VE GUARANTEED THAT TRAFFIC WILL ONLY COME FROM TRUSTED ORIGINS
# https://symfony.com/doc/6.4/deployment/proxies.html
APP_TRUSTED_PROXIES='127.0.0.1,REMOTE_ADDR'
###< symfony/framework-bundle ###

###> doctrine/doctrine-bundle ###
Expand Down Expand Up @@ -69,6 +72,7 @@ OAUTH_PRIVATE_KEY=%kernel.project_dir%/config/jwt/private.pem
OAUTH_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
OAUTH_PASSPHRASE=df7ec1f514c44825926e3dabaf34e3f5
OAUTH_ENCRYPTION_KEY=325b6ce98c009bb83e885657ec08d142
OAUTH_ACCESS_TOKEN_TTL=PT1H
###< league/oauth2-server-bundle ###

###> knpuniversity/oauth2-client-bundle ###
Expand Down
2 changes: 2 additions & 0 deletions config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ framework:
headers:
'User-Agent': 'Platoniq Goteo-v4-API'

trusted_proxies: '%env(APP_TRUSTED_PROXIES)%'

when@test:
framework:
test: true
Expand Down
1 change: 1 addition & 0 deletions config/packages/league_oauth2_server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ league_oauth2_server:
client:
classname: App\Entity\OAuth2Client
authorization_server:
access_token_ttl: '%env(OAUTH_ACCESS_TOKEN_TTL)%'
private_key: '%env(resolve:OAUTH_PRIVATE_KEY)%'
private_key_passphrase: '%env(resolve:OAUTH_PASSPHRASE)%'
encryption_key: '%env(resolve:OAUTH_ENCRYPTION_KEY)%'
Expand Down
1 change: 1 addition & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
env(OAUTH_ACCESS_TOKEN_TTL): PT1H

services:
# default configuration for services in *this* file
Expand Down
40 changes: 40 additions & 0 deletions migrations/Version20261006114714.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20261006114714 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add review, review_area and review_comment tables';
}

public function up(Schema $schema): void
{
$this->addSql('CREATE TABLE review (id INT AUTO_INCREMENT NOT NULL, project_id INT NOT NULL, reviewer_id INT DEFAULT NULL, type VARCHAR(255) NOT NULL, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, INDEX IDX_794381C6166D1F9C (project_id), INDEX IDX_794381C670574616 (reviewer_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE review_area (id INT AUTO_INCREMENT NOT NULL, review_id INT NOT NULL, title VARCHAR(255) NOT NULL, summary LONGTEXT DEFAULT NULL, risk VARCHAR(255) NOT NULL, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, INDEX IDX_352070703E2E969B (review_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE review_comment (id INT AUTO_INCREMENT NOT NULL, author_id INT DEFAULT NULL, area_id INT NOT NULL, body LONGTEXT NOT NULL, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, INDEX IDX_F9AE69BF675F31B (author_id), INDEX IDX_F9AE69BBD0F409C (area_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE review ADD CONSTRAINT FK_794381C6166D1F9C FOREIGN KEY (project_id) REFERENCES project (id)');
$this->addSql('ALTER TABLE review ADD CONSTRAINT FK_794381C670574616 FOREIGN KEY (reviewer_id) REFERENCES user (id)');
$this->addSql('ALTER TABLE review_area ADD CONSTRAINT FK_352070703E2E969B FOREIGN KEY (review_id) REFERENCES review (id)');
$this->addSql('ALTER TABLE review_comment ADD CONSTRAINT FK_F9AE69BF675F31B FOREIGN KEY (author_id) REFERENCES user (id)');
$this->addSql('ALTER TABLE review_comment ADD CONSTRAINT FK_F9AE69BBD0F409C FOREIGN KEY (area_id) REFERENCES review_area (id)');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE review DROP FOREIGN KEY FK_794381C6166D1F9C');
$this->addSql('ALTER TABLE review DROP FOREIGN KEY FK_794381C670574616');
$this->addSql('ALTER TABLE review_area DROP FOREIGN KEY FK_352070703E2E969B');
$this->addSql('ALTER TABLE review_comment DROP FOREIGN KEY FK_F9AE69BF675F31B');
$this->addSql('ALTER TABLE review_comment DROP FOREIGN KEY FK_F9AE69BBD0F409C');
$this->addSql('DROP TABLE review');
$this->addSql('DROP TABLE review_area');
$this->addSql('DROP TABLE review_comment');
}
}
32 changes: 32 additions & 0 deletions migrations/Version20261007154315.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20261007154315 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add theme tables';
}

public function up(Schema $schema): void
{
$this->addSql('CREATE TABLE project_theme (project_id INT NOT NULL, theme_id INT NOT NULL, INDEX IDX_8420EE96166D1F9C (project_id), INDEX IDX_8420EE9659027487 (theme_id), PRIMARY KEY(project_id, theme_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE theme (id INT AUTO_INCREMENT NOT NULL, slug VARCHAR(56) NOT NULL, name VARCHAR(255) NOT NULL, locales JSON NOT NULL COMMENT \'(DC2Type:json)\', UNIQUE INDEX UNIQ_9775E708989D9B62 (slug), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE project_theme ADD CONSTRAINT FK_8420EE96166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE project_theme ADD CONSTRAINT FK_8420EE9659027487 FOREIGN KEY (theme_id) REFERENCES theme (id) ON DELETE CASCADE');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE project_theme DROP FOREIGN KEY FK_8420EE96166D1F9C');
$this->addSql('ALTER TABLE project_theme DROP FOREIGN KEY FK_8420EE9659027487');
$this->addSql('DROP TABLE project_theme');
$this->addSql('DROP TABLE theme');
}
}
5 changes: 2 additions & 3 deletions src/ApiResource/CategoryApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
use Symfony\Component\Validator\Constraints as Assert;

/**
* A Category can be used by other resources as a "topic intent".\
* For example. Projects might relate with up to 2 Categories, which are used by the Project
* as a way to describe itself and can be used to discover similar Projects.\
* A Category, like in books, is a way of grouping resources by type, genre, audience, or subject, for example:
* science-fiction, biography, fantasy, etc.\
* \
* Categories can only be modified by users with the role "ROLE_ADMIN", but can usually
* be referenced by non-admin users in their own resources, such as Project owners.
Expand Down
11 changes: 11 additions & 0 deletions src/ApiResource/Project/ProjectApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use App\ApiResource\CategoryApiResource;
use App\ApiResource\LocalizedApiResourceTrait;
use App\ApiResource\Matchfunding\MatchCallSubmissionApiResource;
use App\ApiResource\ThemeApiResource;
use App\ApiResource\TimestampedCreationApiResource;
use App\ApiResource\TimestampedUpdationApiResource;
use App\ApiResource\User\UserApiResource;
Expand Down Expand Up @@ -134,6 +135,16 @@ class ProjectApiResource
#[API\ApiFilter(filterClass: SearchFilter::class, strategy: 'exact')]
public array $categories;

/**
* A list of the available Themes of this Project.
*
* @var ThemeApiResource[]
*/
#[Assert\NotBlank()]
#[API\ApiProperty(writableLink: false)]
#[API\ApiFilter(filterClass: SearchFilter::class, strategy: 'exact')]
public array $themes;

/**
* ISO 3166 data about the Project's territory of interest.
*/
Expand Down
57 changes: 57 additions & 0 deletions src/ApiResource/Project/ReviewApiResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace App\ApiResource\Project;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata as API;
use App\ApiResource\TimestampedCreationApiResource;
use App\ApiResource\TimestampedUpdationApiResource;
use App\ApiResource\User\UserApiResource;
use App\Entity\Project\Review;
use App\Entity\Project\ReviewType;
use App\State\ApiResourceStateProcessor;
use App\State\ApiResourceStateProvider;

/**
* ProjectReviews are launched as health-checks for Projects.\
* \
* The reviews are focused on certain aspects of a Project's lifecycle. The types `campaign` and `financial` reviews
* are to evaluate the fitness of a Project before being greenlit for campaigning or the legitimacy of their raised funds, respectively.\
* \
* ProjectReview resources cannot be manually created, they are created automatically when a Project moves into a "to review" status:
* - `to_campaign_review`: will launch a related ProjectReview of `campaign` type
* - `to_financial_review`: will launch a related ProjectReview of `financial` type.
*/
#[API\ApiResource(
shortName: 'ProjectReview',
stateOptions: new Options(entityClass: Review::class),
provider: ApiResourceStateProvider::class,
processor: ApiResourceStateProcessor::class
)]
#[API\GetCollection()]
#[API\Get()]
#[API\Delete()]
#[API\Patch()]
class ReviewApiResource
{
use TimestampedCreationApiResource;
use TimestampedUpdationApiResource;

#[API\ApiProperty(identifier: true, writable: false)]
public int $id;

#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public ProjectApiResource $project;

#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public UserApiResource $reviewer;

#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public ReviewType $type;

/**
* @var ReviewAreaApiResource[]
*/
public array $areas;
}
54 changes: 54 additions & 0 deletions src/ApiResource/Project/ReviewAreaApiResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace App\ApiResource\Project;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata as API;
use App\ApiResource\TimestampedCreationApiResource;
use App\ApiResource\TimestampedUpdationApiResource;
use App\Entity\Project\ReviewArea;
use App\Entity\Project\ReviewAreaRisk;
use App\State\ApiResourceStateProcessor;
use App\State\ApiResourceStateProvider;

/**
* A ProjectReviewArea represents one specific topic of evaluation for ProjectReviews.\
* \
* Conversations, feedback and evolution of the ProjectReview must happen around specific areas of review.\
* Each area holds an associated risk, which represents the trust the reviewer has for the reviewed Project's health in that area,
* areas can only be updated by the assigned reviewer or an user with `ROLE_ADMIN`.
*/
#[API\ApiResource(
shortName: 'ProjectReviewArea',
stateOptions: new Options(entityClass: ReviewArea::class),
provider: ApiResourceStateProvider::class,
processor: ApiResourceStateProcessor::class,
)]
#[API\GetCollection()]
#[API\Post(security: 'is_granted("ROLE_ADMIN")')]
#[API\Get(security: 'is_granted("REVIEWAREA_VIEW", object)')]
#[API\Patch(security: 'is_granted("REVIEWAREA_EDIT", object)')]
#[API\Delete(security: 'is_granted("REVIEWAREA_EDIT", object)')]
class ReviewAreaApiResource
{
use TimestampedCreationApiResource;
use TimestampedUpdationApiResource;

#[API\ApiProperty(identifier: true, writable: false)]
public int $id;

#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public ReviewApiResource $review;

public string $title;

public string $summary;

public ReviewAreaRisk $risk;

/**
* @var ReviewCommentApiResource[]
*/
public array $comments;
}
50 changes: 50 additions & 0 deletions src/ApiResource/Project/ReviewCommentApiResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\ApiResource\Project;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata as API;
use App\ApiResource\TimestampedCreationApiResource;
use App\ApiResource\TimestampedUpdationApiResource;
use App\ApiResource\User\UserApiResource;
use App\Entity\Project\ReviewComment;
use App\State\ApiResourceStateProcessor;
use App\State\ApiResourceStateProvider;
use App\Validator\UserOwned;
use Symfony\Component\Validator\Constraints as Assert;

/**
* ProjectReviewComments hold the conversation between the reviewer and the reviewed Project owner.
*/
#[API\ApiResource(
shortName: 'ProjectReviewComment',
stateOptions: new Options(entityClass: ReviewComment::class),
provider: ApiResourceStateProvider::class,
processor: ApiResourceStateProcessor::class,
)]
#[API\GetCollection()]
#[API\Post(securityPostDenormalize: 'is_granted("REVIEWAREA_VIEW", object.area)')]
#[API\Get(security: 'is_granted("REVIEWAREA_VIEW", object.area)')]
#[API\Delete(security: 'is_granted("REVIEWAREA_VIEW", object.area)')]
class ReviewCommentApiResource
{
use TimestampedCreationApiResource;
use TimestampedUpdationApiResource;

#[API\ApiProperty(identifier: true, writable: false)]
public int $id;

#[Assert\NotBlank()]
#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public ReviewAreaApiResource $area;

#[UserOwned()]
#[Assert\NotBlank()]
#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public UserApiResource $author;

#[Assert\NotBlank()]
#[Assert\Length(min: 15)]
public string $body;
}
64 changes: 64 additions & 0 deletions src/ApiResource/ThemeApiResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace App\ApiResource;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata as API;
use App\Entity\Theme;
use App\State\ApiResourceStateProcessor;
use App\State\ApiResourceStateProvider;
use App\State\ThemeStateProvider;
use Symfony\Component\Validator\Constraints as Assert;

/**
* A Theme, like in books, works as a "topic intent" grouping, for example:
* friendship, good vs. evil, power and corruption, etc.\
* \
* Themes can only be modified by users with the role "ROLE_ADMIN", but can usually
* be referenced by non-admin users in their own resources, such as Project owners.
*/
#[API\ApiResource(
shortName: 'Theme',
stateOptions: new Options(entityClass: Theme::class),
provider: ApiResourceStateProvider::class,
processor: ApiResourceStateProcessor::class,
)]
#[API\GetCollection()]
#[API\Post(security: 'is_granted("ROLE_ADMIN")')]
#[API\Get(
provider: ThemeStateProvider::class,
uriTemplate: '/themes/{idOrSlug}',
uriVariables: [
'idOrSlug' => new API\Link(
description: 'Theme identifier or slug',
),
]
)]
#[API\Patch(security: 'is_granted("ROLE_ADMIN")')]
#[API\Delete(security: 'is_granted("ROLE_ADMIN")')]
class ThemeApiResource
{
use LocalizedApiResourceTrait;

/**
* This value will identify this Theme in relationships with other resources.
*/
#[API\ApiProperty(identifier: true)]
public string $id;

/**
* A unique, non white space, string identifier for this Theme.
*/
#[API\ApiProperty(writable: false)]
#[API\ApiFilter(SearchFilter::class, strategy: 'exact')]
public string $slug;

/**
* A human-readable self-descriptive string of what this Theme is about.
*/
#[Assert\NotBlank()]
#[API\ApiProperty()]
#[API\ApiFilter(SearchFilter::class, strategy: 'partial')]
public string $name;
}
Loading
Loading