Compare commits

..

No commits in common. "main" and "1.1.1" have entirely different histories.
main ... 1.1.1

131 changed files with 21140 additions and 37217 deletions

10
.env
View file

@ -1,5 +1,5 @@
# In all environments, the following files are loaded if they exist, # In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former: # the later taking precedence over the former:
# #
# * .env contains default values for the environment variables needed by the app # * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides # * .env.local uncommitted file with local overrides
@ -9,13 +9,13 @@
# Real environment variables win over .env files. # Real environment variables win over .env files.
# #
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
# #
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
###> symfony/framework-bundle ### ###> symfony/framework-bundle ###
APP_ENV=prod APP_ENV=dev
APP_SECRET=7189792ca5da6b84aff72ec1c63d95ae APP_SECRET=7189792ca5da6b84aff72ec1c63d95ae
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS='^localhost|example\.com$'
###< symfony/framework-bundle ### ###< symfony/framework-bundle ###

14
.gitignore vendored
View file

@ -12,17 +12,3 @@
###> symfony/web-server-bundle ### ###> symfony/web-server-bundle ###
/.web-server-pid /.web-server-pid
###< symfony/web-server-bundle ### ###< symfony/web-server-bundle ###
###> symfony/phpunit-bridge ###
.phpunit
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
/bin/phpunit
/tests/
/tests/bootstrap.php
/var/
/vendor/
/.env.test
/composer
/phpunit.xml.dist

View file

@ -1,56 +0,0 @@
FROM composer as composer
COPY --chown=nobody . /app
RUN composer install --optimize-autoloader --no-interaction --no-progress
FROM alpine:3.19
# Install packages and remove default server definition
RUN apk add --no-cache \
curl \
nginx \
php83 \
php83-ctype \
php83-curl \
php83-dom \
php83-fpm \
php83-intl \
php83-mbstring \
php83-session \
php83-tokenizer \
php83-simplexml \
supervisor
# Configure nginx - http
COPY docker_config/nginx.conf /etc/nginx/nginx.conf
# Configure nginx - default server
COPY docker_config/conf.d /etc/nginx/conf.d/
# Configure PHP-FPM
ENV PHP_INI_DIR /etc/php83
COPY docker_config/fpm-pool.conf ${PHP_INI_DIR}/php-fpm.d/www.conf
COPY docker_config/php.ini ${PHP_INI_DIR}/conf.d/custom.ini
# Configure supervisord
COPY docker_config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Add application
COPY --chown=nobody --from=composer /app/ /var/www/fediplan/
# Make sure files/folders needed by the processes are accessable when they run under the nobody user
RUN chown -R nobody.nobody /var/www/fediplan /run /var/lib/nginx /var/log/nginx
# Create symlink for php
RUN ln -s /usr/bin/php83 /usr/bin/php
# Switch to use a non-root user from here on
USER nobody
# Expose the port nginx is reachable on
EXPOSE 8080
# Let supervisord start nginx & php-fpm
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
# Configure a healthcheck to validate that everything is up&running
HEALTHCHECK --timeout=10s CMD curl --silent --fail http://127.0.0.1:8080/fpm-ping || exit 1

View file

@ -1,79 +1,25 @@
**If you want to contribute to a _translation_:**[![Crowdin](https://badges.crowdin.net/fediplan/localized.svg)](https://crowdin.com/project/fediplan) **If you want to contribute to a _translation_:**[![Crowdin](https://badges.crowdin.net/fediplan/localized.svg)](https://crowdin.com/project/fediplan)
## How to install FediPlan ### How to install FediPlan
There are 2 methods to run Fediplan **1 - Clone the repository**
1. Build and run Docker image
2. Manual install
### 1. Build and run Docker image **2 - Install vendors:**
#### Required programs `composer install -o`
- `git`
- `docker`
#### Steps PS: You need to install `composer`, just use:
1. Install required programs `apt install composer`
2. Clone this repo<br> Or you can do that with the following commands:
`git clone https://framagit.org/tom79/fediplan.git fediplan`
3. Build the Docker image<br> ```
`docker build --tag fediplan fediplan` php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
4. Run the docker image<br> php composer-setup.php
`docker run --detach --restart unless-stopped --name fediplan fediplan:latest` php -r "unlink('composer-setup.php');"
```
5. Find the IP<br>
`docker inspect fediplan | grep IPAddress`
6. Fediplan should be available at _<ip_address>:8080_
### 2. Manual install
#### Required programs
- `git`
- `php 8.3` with these extensions:
For Composer
- `openssl`
- `phar`
- `iconv`
- `xml`
- `simplexml`
- `xmlwriter`
For running
- `ctype`
- `curl`
- `dom`
- `fpm`
- `intl`
- `mbstring`
- `simplexml`
- `session`
- `tokenizer`
- `composer` ([getcomposer.org/download](https://getcomposer.org/download/))
#### Steps
1. Install required programs
2. Clone this repo<br>
`git clone https://framagit.org/tom79/fediplan.git fediplan`
3. Install vendors<br>
`php composer.phar install --optimize-autoloader --working-dir=fediplan`
4. Point your server software to `fediplan/public` folder
### Support My work
[fedilab.app/page/donations](https://fedilab.app/page/donations/)
### Credits
Docker configurations are based on [github.com/TrafeX/docker-php-nginx](https://github.com/TrafeX/docker-php-nginx)
See: [Download Composer](https://getcomposer.org/download/) See: [Download Composer](https://getcomposer.org/download/)

View file

@ -1,10 +0,0 @@
import './bootstrap.js';
/*
* Welcome to your app's main JavaScript file!
*
* This file will be included onto the page via the importmap() Twig function,
* which should already be in your base.html.twig.
*/
import './styles/app.css';
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');

5
assets/bootstrap.js vendored
View file

@ -1,5 +0,0 @@
import { startStimulusApp } from '@symfony/stimulus-bundle';
const app = startStimulusApp();
// register any custom, 3rd party controllers here
// app.register('some_controller_name', SomeImportedController);

View file

@ -1,15 +0,0 @@
{
"controllers": {
"@symfony/ux-turbo": {
"turbo-core": {
"enabled": true,
"fetch": "eager"
},
"mercure-turbo-stream": {
"enabled": false,
"fetch": "eager"
}
}
},
"entrypoints": []
}

View file

@ -1,16 +0,0 @@
import { Controller } from '@hotwired/stimulus';
/*
* This is an example Stimulus controller!
*
* Any element with a data-controller="hello" attribute will cause
* this controller to be executed. The name "hello" comes from the filename:
* hello_controller.js -> "hello"
*
* Delete this file or adapt it for your use!
*/
export default class extends Controller {
connect() {
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
}
}

View file

@ -1 +0,0 @@
{"base_url":"","routes":{"load_more":{"tokens":[["variable","\/","[^\/]++","max_id",true],["text","\/scheduled\/messages"],["variable","\/","[^\/]++","_locale",true]],"defaults":{"max_id":null,"_locale":""},"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"delete_message":{"tokens":[["variable","\/","[^\/]++","id",true],["text","\/scheduled\/delete\/messages"],["variable","\/","fr|en|nl|pt-PT|pt-BR|de|ar|it|ca|ja|pl|ru|uk","_locale",true]],"defaults":{"_locale":"en","id":null},"requirements":{"_locale":"fr|en|nl|pt-PT|pt-BR|de|ar|it|ca|ja|pl|ru|uk"},"hosttokens":[],"methods":["POST"],"schemes":[]}},"prefix":"","host":"localhost","port":"","scheme":"http","locale":""}

View file

@ -1 +0,0 @@
{"base_url":"","routes":{"load_more":{"tokens":[["variable","\/","[^\/]++","max_id",true],["text","\/scheduled\/messages"],["variable","\/","[^\/]++","_locale",true]],"defaults":{"max_id":null,"_locale":""},"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"delete_message":{"tokens":[["variable","\/","[^\/]++","id",true],["text","\/scheduled\/delete\/messages"],["variable","\/","fr|en|nl|pt-PT|pt-BR|de|ar|it|ca|ja|pl|ru|uk","_locale",true]],"defaults":{"_locale":"en","id":null},"requirements":{"_locale":"fr|en|nl|pt-PT|pt-BR|de|ar|it|ca|ja|pl|ru|uk"},"hosttokens":[],"methods":["POST"],"schemes":[]}},"prefix":"","host":"localhost","port":"","scheme":"http","locale":""}

View file

@ -1,3 +0,0 @@
body {
background-color: skyblue;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,22 +0,0 @@
<?php return array (
'@hotwired/stimulus' =>
array (
'version' => '3.2.2',
'dependencies' =>
array (
),
'extraFiles' =>
array (
),
),
'@hotwired/turbo' =>
array (
'version' => '7.3.0',
'dependencies' =>
array (
),
'extraFiles' =>
array (
),
),
);

View file

@ -3,19 +3,40 @@
use App\Kernel; use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;
if (!is_dir(dirname(__DIR__).'/vendor')) { if (false === in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
throw new LogicException('Dependencies are missing. Try running "composer install".'); echo 'Warning: The console should be invoked via the CLI version of PHP, not the '.\PHP_SAPI.' SAPI'.\PHP_EOL;
} }
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) { set_time_limit(0);
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
require dirname(__DIR__).'/vendor/autoload.php';
if (!class_exists(Application::class)) {
throw new RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
} }
require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; $input = new ArgvInput();
if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) {
putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
}
return function (array $context) { if ($input->hasParameterOption('--no-debug', true)) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
}
return new Application($kernel); require dirname(__DIR__).'/config/bootstrap.php';
};
if ($_SERVER['APP_DEBUG']) {
umask(0000);
if (class_exists(Debug::class)) {
Debug::enable();
}
}
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$application = new Application($kernel);
$application->run($input);

View file

@ -1,54 +1,35 @@
{ {
"type": "project", "type": "project",
"license": "proprietary", "license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": { "require": {
"php": ">=8.2", "php": "^7.1.3",
"ext-ctype": "*", "ext-ctype": "*",
"ext-curl": "*",
"ext-iconv": "*", "ext-iconv": "*",
"craue/formflow-bundle": "*", "craue/formflow-bundle": "^3.2",
"curl/curl": "^2.5", "doctrine/collections": "^1.6",
"friendsofsymfony/jsrouting-bundle": "*", "friendsofsymfony/jsrouting-bundle": "^2.4",
"phpdocumentor/reflection-docblock": "^5.4", "sensio/framework-extra-bundle": "^5.4",
"phpstan/phpdoc-parser": "^1.29", "symfony/asset": "4.3.*",
"symfony/asset": "7.0.*", "symfony/console": "4.3.*",
"symfony/asset-mapper": "7.0.*", "symfony/debug": "4.3.*",
"symfony/console": "7.0.*", "symfony/dotenv": "4.3.*",
"symfony/dotenv": "7.0.*", "symfony/flex": "^1.3.1",
"symfony/expression-language": "7.0.*", "symfony/framework-bundle": "4.3.*",
"symfony/flex": "^2", "symfony/polyfill-intl-messageformatter": "^1.15",
"symfony/form": "7.0.*", "symfony/security-bundle": "4.3.*",
"symfony/framework-bundle": "7.0.*", "symfony/translation": "4.3.*",
"symfony/http-client": "7.0.*", "symfony/twig-bundle": "4.3.*",
"symfony/intl": "7.0.*", "symfony/yaml": "4.3.*",
"symfony/mime": "7.0.*", "twig/extensions": "^1.5",
"symfony/monolog-bundle": "^3.0", "ext-curl": "*",
"symfony/notifier": "7.0.*", "ext-json": "*"
"symfony/process": "7.0.*", },
"symfony/property-access": "7.0.*", "require-dev": {
"symfony/property-info": "7.0.*", "symfony/web-server-bundle": "4.3.*"
"symfony/runtime": "7.0.*",
"symfony/security-bundle": "7.0.*",
"symfony/serializer": "7.0.*",
"symfony/stimulus-bundle": "^2.17",
"symfony/string": "7.0.*",
"symfony/translation": "7.0.*",
"symfony/twig-bundle": "7.0.*",
"symfony/ux-turbo": "^2.17",
"symfony/validator": "7.0.*",
"symfony/web-link": "7.0.*",
"symfony/yaml": "7.0.*",
"twig/extra-bundle": "^3.20",
"twig/intl-extra": "^3.20",
"twig/twig": "v3.15.0"
}, },
"config": { "config": {
"allow-plugins": { "preferred-install": {
"php-http/discovery": true, "*": "dist"
"symfony/flex": true,
"symfony/runtime": true
}, },
"sort-packages": true "sort-packages": true
}, },
@ -63,22 +44,17 @@
} }
}, },
"replace": { "replace": {
"paragonie/random_compat": "2.*",
"symfony/polyfill-ctype": "*", "symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*", "symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*", "symfony/polyfill-php71": "*",
"symfony/polyfill-php73": "*", "symfony/polyfill-php70": "*",
"symfony/polyfill-php74": "*", "symfony/polyfill-php56": "*"
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*",
"symfony/polyfill-php82": "*"
}, },
"scripts": { "scripts": {
"auto-scripts": { "auto-scripts": {
"cache:clear": "symfony-cmd", "cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd", "assets:install %PUBLIC_DIR%": "symfony-cmd"
"assets:install --symlink public": "symfony-cmd",
"importmap:install": "symfony-cmd",
"asset-map:compile": "symfony-cmd"
}, },
"post-install-cmd": [ "post-install-cmd": [
"@auto-scripts" "@auto-scripts"
@ -93,17 +69,7 @@
"extra": { "extra": {
"symfony": { "symfony": {
"allow-contrib": false, "allow-contrib": false,
"require": "7.0.*" "require": "4.3.*"
} }
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"symfony/browser-kit": "7.0.*",
"symfony/css-selector": "7.0.*",
"symfony/debug-bundle": "7.0.*",
"symfony/maker-bundle": "^1.0",
"symfony/phpunit-bridge": "^7.0",
"symfony/stopwatch": "7.0.*",
"symfony/web-profiler-bundle": "7.0.*"
} }
} }

7983
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,15 +2,10 @@
return [ return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true],
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
FOS\JsRoutingBundle\FOSJsRoutingBundle::class => ['all' => true], FOS\JsRoutingBundle\FOSJsRoutingBundle::class => ['all' => true],
Craue\FormFlowBundle\CraueFormFlowBundle::class => ['all' => true], Craue\FormFlowBundle\CraueFormFlowBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
]; ];

View file

@ -1,5 +0,0 @@
framework:
asset_mapper:
# The paths to make available to the asset mapper.
paths:
- assets/

View file

@ -1,5 +0,0 @@
when@dev:
debug:
# Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
# See the "server:dump" command to start a new server.
dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"

View file

@ -0,0 +1,3 @@
framework:
router:
strict_requirements: true

View file

@ -1,16 +1,16 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework: framework:
secret: '%env(APP_SECRET)%' secret: '%env(APP_SECRET)%'
#csrf_protection: true #csrf_protection: true
#http_method_override: true
# Note that the session will be started ONLY if you read or write from it. # Enables session support. Note that the session will ONLY be started if you read or write from it.
session: true # Remove or comment this section to explicitly disable session support.
session:
handler_id: null
cookie_secure: auto
cookie_samesite: lax
#esi: true #esi: true
#fragments: true #fragments: true
php_errors:
when@test: log: true
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file

View file

@ -1,10 +1,4 @@
framework: framework:
router: router:
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands. strict_requirements: null
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands utf8: true
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null

View file

@ -1,19 +1,13 @@
security: security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers: providers:
# used to reload user from session & other features (e.g. switch_user) in_memory: { memory: ~ }
app_user_provider:
id: App\Security\UserProvider
firewalls: firewalls:
dev: dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/ pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false security: false
main: main:
lazy: true anonymous: ~
provider: app_user_provider
logout: logout:
path: logout path: logout
@ -29,16 +23,3 @@ security:
# - { path: ^/admin, roles: ROLE_ADMIN } # - { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/(%languages%)?/schedule, roles: ROLE_USER } - { path: ^/(%languages%)?/schedule, roles: ROLE_USER }
- { path: ^/(%languages%)?/scheduled, roles: ROLE_USER } - { path: ^/(%languages%)?/scheduled, roles: ROLE_USER }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon

View file

@ -0,0 +1,3 @@
sensio_framework_extra:
router:
annotations: false

View file

@ -0,0 +1,4 @@
framework:
test: true
session:
storage_id: session.storage.mock_file

View file

@ -0,0 +1,3 @@
framework:
router:
strict_requirements: true

View file

@ -0,0 +1,3 @@
framework:
validation:
not_compromised_password: false

View file

@ -1,6 +1,4 @@
twig: twig:
file_name_pattern: '*.twig' default_path: '%kernel.project_dir%/templates'
debug: '%kernel.debug%'
when@test: strict_variables: '%kernel.debug%'
twig:
strict_variables: true

View file

@ -1,11 +1,8 @@
framework: framework:
validation: validation:
# Enables validator auto-mapping support. email_validation_mode: html5
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
#auto_mapping:
# App\Entity\: []
when@test: # Enables validator auto-mapping support.
framework: # For instance, basic validation constraints will be inferred from Doctrine's metadata.
validation: #auto_mapping:
not_compromised_password: false # App\Entity\: []

View file

@ -1,17 +0,0 @@
when@dev:
web_profiler:
toolbar: true
intercept_redirects: false
framework:
profiler:
only_exceptions: false
collect_serializer_data: true
when@test:
web_profiler:
toolbar: false
intercept_redirects: false
framework:
profiler: { collect: false }

View file

@ -1,5 +0,0 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
}

View file

@ -1,5 +1,3 @@
controllers: #index:
resource: # path: /
path: ../src/Controller/ # controller: App\Controller\DefaultController::index
namespace: App\Controller
type: attribute

View file

@ -0,0 +1,3 @@
controllers:
resource: ../../src/Controller/
type: annotation

View file

@ -0,0 +1,3 @@
_errors:
resource: '@TwigBundle/Resources/config/routing/errors.xml'
prefix: /_error

View file

@ -1,4 +0,0 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

View file

@ -1,3 +0,0 @@
_security_logout:
resource: security.route_loader.logout
type: service

View file

@ -1,8 +0,0 @@
when@dev:
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler

View file

@ -4,7 +4,7 @@
# Put parameters here that don't need to change on each machine where the app is deployed # Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters: parameters:
allowed_language: "fr|en|nl|pt-PT|pt-BR|de|ar|it|ca|ja|pl|ru|uk" allowed_language: "fr|en|nl|pt-PT|pt-BR|de|ar|it|ca|ja"
languages: "(%allowed_language%)?" languages: "(%allowed_language%)?"
services: services:
# default configuration for services in *this* file # default configuration for services in *this* file
@ -16,10 +16,7 @@ services:
# this creates a service per class whose id is the fully-qualified class name # this creates a service per class whose id is the fully-qualified class name
App\: App\:
resource: '../src/*' resource: '../src/*'
exclude: exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# controllers are imported separately to make sure services can be injected # controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class # as action arguments even if you don't extend any base controller class

View file

@ -1,56 +0,0 @@
# Default server definition
server {
listen [::]:8080 default_server;
listen 8080 default_server;
server_name _;
sendfile off;
tcp_nodelay on;
absolute_redirect off;
root /var/www/fediplan/public;
index index.php index.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.php
try_files $uri $uri/ /index.php?q=$uri&$args;
}
# Redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/lib/nginx/html;
}
# Pass the PHP scripts to PHP-FPM listening on php-fpm.sock
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
}
# Set the cache-control headers on assets to cache for 5 days
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
expires 5d;
}
# Deny access to . files, for security
location ~ /\. {
log_not_found off;
deny all;
}
# Allow fpm ping and status from localhost
location ~ ^/(fpm-status|fpm-ping)$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm.sock;
}
}

View file

@ -1,56 +0,0 @@
[global]
; Log to stderr
error_log = /dev/stderr
[www]
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
; a specific port;
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses
; (IPv6 and IPv4-mapped) on a specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /run/php-fpm.sock
; Enable status page
pm.status_path = /fpm-status
; Ondemand process manager
pm = ondemand
; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 100
; The number of seconds after which an idle process will be killed.
; Note: Used only when pm is set to 'ondemand'
; Default Value: 10s
pm.process_idle_timeout = 10s;
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For
; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
; Default Value: 0
pm.max_requests = 1000
; Make sure the FPM workers can reach the environment variables for configuration
clear_env = no
; Catch output from PHP
catch_workers_output = yes
; Remove the 'child 10 said into stderr' prefix in the log and only show the actual message
decorate_workers_output = no
; Enable ping page to use in healthcheck
ping.path = /fpm-ping

View file

@ -1,47 +0,0 @@
worker_processes auto;
error_log stderr warn;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
# Threat files with a unknown filetype as binary
default_type application/octet-stream;
# Define custom log format to include reponse times
log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $pipe $upstream_cache_status';
access_log /dev/stdout main_timed;
error_log /dev/stderr notice;
keepalive_timeout 65;
# Write temporary files to /tmp so they can be created as a non-privileged user
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
# Hide headers that identify the server to prevent information leakage
proxy_hide_header X-Powered-By;
fastcgi_hide_header X-Powered-By;
server_tokens off;
# Enable gzip compression by default
gzip on;
gzip_proxied any;
# Based on CloudFlare's recommended settings
gzip_types text/richtext text/plain text/css text/x-script text/x-component text/x-java-source text/x-markdown application/javascript application/x-javascript text/javascript text/js image/x-icon image/vnd.microsoft.icon application/x-perl application/x-httpd-cgi text/xml application/xml application/rss+xml application/vnd.api+json application/x-protobuf application/json multipart/bag multipart/mixed application/xhtml+xml font/ttf font/otf font/x-woff image/svg+xml application/vnd.ms-fontobject application/ttf application/x-ttf application/otf application/x-otf application/truetype application/opentype application/x-opentype application/font-woff application/eot application/font application/font-sfnt application/wasm application/javascript-binast application/manifest+json application/ld+json application/graphql+json application/geo+json;
gzip_vary on;
gzip_disable "msie6";
# Include server configs
include /etc/nginx/conf.d/*.conf;
}

View file

@ -1,3 +0,0 @@
[Date]
date.timezone="UTC"
expose_php= Off

View file

@ -1,23 +0,0 @@
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:php-fpm]
command=php-fpm83 -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0
[program:nginx]
command=nginx -g 'daemon off;'
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0

View file

@ -1,28 +0,0 @@
<?php
/**
* Returns the importmap for this application.
*
* - "path" is a path inside the asset mapper system. Use the
* "debug:asset-map" command to see the full list of paths.
*
* - "entrypoint" (JavaScript only) set to true for any module that will
* be used as an "entrypoint" (and passed to the importmap() Twig function).
*
* The "importmap:require" command can be used to add new entries to this file.
*/
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
'@hotwired/stimulus' => [
'version' => '3.2.2',
],
'@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
],
'@hotwired/turbo' => [
'version' => '7.3.0',
],
];

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,268 +1,57 @@
/*! /*!
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/) * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors * Copyright 2011-2018 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/ */
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #c4c8cb;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #fff;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: #6ea8fe;
--bs-secondary-text-emphasis: #a7acb1;
--bs-success-text-emphasis: #75b798;
--bs-info-text-emphasis: #6edff6;
--bs-warning-text-emphasis: #ffda6a;
--bs-danger-text-emphasis: #ea868f;
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #161719;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #41464b;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #087990;
--bs-warning-border-subtle: #997404;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #8bb9fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
--bs-form-valid-border-color: #75b798;
--bs-form-invalid-color: #ea868f;
--bs-form-invalid-border-color: #ea868f;
}
*, *,
*::before, *::before,
*::after { *::after {
box-sizing: border-box; box-sizing: border-box;
} }
@media (prefers-reduced-motion: no-preference) { html {
:root { font-family: sans-serif;
scroll-behavior: smooth; line-height: 1.15;
} -webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@-ms-viewport {
width: device-width;
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
} }
body { body {
margin: 0; margin: 0;
font-family: var(--bs-body-font-family); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: var(--bs-body-font-size); font-size: 1rem;
font-weight: var(--bs-body-font-weight); font-weight: 400;
line-height: var(--bs-body-line-height); line-height: 1.5;
color: var(--bs-body-color); color: #212529;
text-align: var(--bs-body-text-align); text-align: left;
background-color: var(--bs-body-bg); background-color: #fff;
-webkit-text-size-adjust: 100%; }
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
[tabindex="-1"]:focus {
outline: 0 !important;
} }
hr { hr {
margin: 1rem 0; box-sizing: content-box;
color: inherit; height: 0;
border: 0; overflow: visible;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
} }
h6, h5, h4, h3, h2, h1 { h1, h2, h3, h4, h5, h6 {
margin-top: 0; margin-top: 0;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
} }
p { p {
@ -270,12 +59,13 @@ p {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
abbr[title] { abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted; -webkit-text-decoration: underline dotted;
text-decoration: underline dotted; text-decoration: underline dotted;
cursor: help; cursor: help;
-webkit-text-decoration-skip-ink: none; border-bottom: 0;
text-decoration-skip-ink: none;
} }
address { address {
@ -284,11 +74,6 @@ address {
line-height: inherit; line-height: inherit;
} }
ol,
ul {
padding-left: 2rem;
}
ol, ol,
ul, ul,
dl { dl {
@ -308,7 +93,7 @@ dt {
} }
dd { dd {
margin-bottom: 0.5rem; margin-bottom: .5rem;
margin-left: 0; margin-left: 0;
} }
@ -316,139 +101,118 @@ blockquote {
margin: 0 0 1rem; margin: 0 0 1rem;
} }
dfn {
font-style: italic;
}
b, b,
strong { strong {
font-weight: bolder; font-weight: bolder;
} }
small { small {
font-size: 0.875em; font-size: 80%;
}
mark {
padding: 0.1875em;
color: var(--bs-highlight-color);
background-color: var(--bs-highlight-bg);
} }
sub, sub,
sup { sup {
position: relative; position: relative;
font-size: 0.75em; font-size: 75%;
line-height: 0; line-height: 0;
vertical-align: baseline; vertical-align: baseline;
} }
sub { sub {
bottom: -0.25em; bottom: -.25em;
} }
sup { sup {
top: -0.5em; top: -.5em;
} }
a { a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); color: #007bff;
text-decoration: underline; text-decoration: none;
} background-color: transparent;
a:hover { -webkit-text-decoration-skip: objects;
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
} }
a:not([href]):not([class]), a:not([href]):not([class]):hover { a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
} }
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre, pre,
code, code,
kbd, kbd,
samp { samp {
font-family: var(--bs-font-monospace); font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em; font-size: 1em;
} }
pre { pre {
display: block;
margin-top: 0; margin-top: 0;
margin-bottom: 1rem; margin-bottom: 1rem;
overflow: auto; overflow: auto;
font-size: 0.875em; -ms-overflow-style: scrollbar;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
} }
figure { figure {
margin: 0 0 1rem; margin: 0 0 1rem;
} }
img, img {
vertical-align: middle;
border-style: none;
}
svg { svg {
overflow: hidden;
vertical-align: middle; vertical-align: middle;
} }
table { table {
caption-side: bottom;
border-collapse: collapse; border-collapse: collapse;
} }
caption { caption {
padding-top: 0.5rem; padding-top: 0.75rem;
padding-bottom: 0.5rem; padding-bottom: 0.75rem;
color: var(--bs-secondary-color); color: #6c757d;
text-align: left; text-align: left;
caption-side: bottom;
} }
th { th {
text-align: inherit; text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
} }
label { label {
display: inline-block; display: inline-block;
margin-bottom: 0.5rem;
} }
button { button {
border-radius: 0; border-radius: 0;
} }
button:focus:not(:focus-visible) { button:focus {
outline: 0; outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
} }
input, input,
@ -462,45 +226,46 @@ textarea {
line-height: inherit; line-height: inherit;
} }
button,
input {
overflow: visible;
}
button, button,
select { select {
text-transform: none; text-transform: none;
} }
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button, button,
[type=button], html [type="button"],
[type=reset], [type="reset"],
[type=submit] { [type="submit"] {
-webkit-appearance: button; -webkit-appearance: button;
} }
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner { button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0; padding: 0;
border-style: none; border-style: none;
} }
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea { textarea {
overflow: auto;
resize: vertical; resize: vertical;
} }
@ -512,55 +277,34 @@ fieldset {
} }
legend { legend {
float: left; display: block;
width: 100%; width: 100%;
max-width: 100%;
padding: 0; padding: 0;
margin-bottom: 0.5rem; margin-bottom: .5rem;
font-size: calc(1.275rem + 0.3vw); font-size: 1.5rem;
line-height: inherit; line-height: inherit;
} color: inherit;
@media (min-width: 1200px) { white-space: normal;
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
} }
::-webkit-datetime-edit-fields-wrapper, progress {
::-webkit-datetime-edit-text, vertical-align: baseline;
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
} }
::-webkit-inner-spin-button { [type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto; height: auto;
} }
[type=search] { [type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px; outline-offset: -2px;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none; -webkit-appearance: none;
} }
::-webkit-color-swatch-wrapper { [type="search"]::-webkit-search-cancel-button,
padding: 0; [type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
} }
::-webkit-file-upload-button { ::-webkit-file-upload-button {
@ -568,30 +312,20 @@ legend + * {
-webkit-appearance: button; -webkit-appearance: button;
} }
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output { output {
display: inline-block; display: inline-block;
} }
iframe {
border: 0;
}
summary { summary {
display: list-item; display: list-item;
cursor: pointer; cursor: pointer;
} }
progress { template {
vertical-align: baseline; display: none;
} }
[hidden] { [hidden] {
display: none !important; display: none !important;
} }
/*# sourceMappingURL=bootstrap-reboot.css.map */ /*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,14 +0,0 @@
/* Copyright Notice
* bootstrap5-toggle v5.1.1
* https://palcarazm.github.io/bootstrap5-toggle/
* @author 2011-2014 Min Hur (https://github.com/minhur)
* @author 2018-2019 Brent Ely (https://github.com/gitbrent)
* @author 2022 Pablo Alcaraz Martínez (https://github.com/palcarazm)
* @funding GitHub Sponsors
* @see https://github.com/sponsors/palcarazm
* @license MIT
* @see https://github.com/palcarazm/bootstrap5-toggle/blob/master/LICENSE
*/
.btn-group-xs>.btn,.btn-xs{padding:.35rem .4rem .25rem .4rem;font-size:.875rem;line-height:.5;border-radius:.2rem}.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-1.25rem;margin-right:.35rem}.toggle{position:relative;overflow:hidden}.toggle:focus>.toggle-group>.btn,.toggle:hover>.toggle-group>.btn{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.toggle:focus>.toggle-group>.toggle-handle,.toggle:hover>.toggle-group>.toggle-handle{background-color:var(--bs-light);opacity:.5}.toggle>input[type=checkbox]{display:none}.toggle>.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;user-select:none;-moz-user-select:none;-webkit-user-select:none}.toggle>.toggle-group>span{cursor:pointer}.toggle.off>.toggle-group{left:-100%}.toggle.indeterminate>.toggle-group{left:-50%}.toggle>.toggle-group>.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}.toggle>.toggle-group>.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0;box-shadow:none}.toggle>.toggle-group>.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px;background-color:var(--bs-light);border-color:var(--bs-light)}.input-group .toggle>.toggle-group>.toggle-off,.input-group .toggle>.toggle-group>.toggle-on{position:absolute}.toggle:not(:hover):not(:focus).btn-outline-primary>.toggle-group>.toggle-handle{background-color:var(--bs-primary);border-color:var(--bs-primary)}.toggle:not(:hover):not(:focus).btn-outline-secondary>.toggle-group>.toggle-handle{background-color:var(--bs-secondary);border-color:var(--bs-secondary)}.toggle:not(:hover):not(:focus).btn-outline-success>.toggle-group>.toggle-handle{background-color:var(--bs-success);border-color:var(--bs-success)}.toggle:not(:hover):not(:focus).btn-outline-danger>.toggle-group>.toggle-handle{background-color:var(--bs-danger);border-color:var(--bs-danger)}.toggle:not(:hover):not(:focus).btn-outline-warning>.toggle-group>.toggle-handle{background-color:var(--bs-warning);border-color:var(--bs-warning)}.toggle:not(:hover):not(:focus).btn-outline-info>.toggle-group>.toggle-handle{background-color:var(--bs-info);border-color:var(--bs-info)}.toggle:not(:hover):not(:focus).btn-outline-light>.toggle-group>.toggle-handle{background-color:var(--bs-light);border-color:var(--bs-light)}.toggle:not(:hover):not(:focus).btn-outline-dark>.toggle-group>.toggle-handle{background-color:var(--bs-dark);border-color:var(--bs-dark)}.toggle.btn{min-width:3.7rem;min-height:2.15rem}.toggle>.toggle-group>.toggle-on.btn{padding-right:1.5rem}.toggle>.toggle-group>.toggle-off.btn{padding-left:1.5rem}.toggle.btn-lg{min-width:5rem;min-height:2.815rem}.toggle>.toggle-group>.toggle-on.btn-lg{padding-right:2rem}.toggle>.toggle-group>.toggle-off.btn-lg{padding-left:2rem}.toggle>.toggle-group>.toggle-handle.btn-lg{width:2.5rem}.toggle.btn-sm{min-width:3.125rem;min-height:1.938rem}.toggle>.toggle-group>.toggle-on.btn-sm{padding-right:1rem}.toggle>.toggle-group>.toggle-off.btn-sm{padding-left:1rem}.toggle.btn-xs{min-width:2.19rem;min-height:1.375rem}.toggle>.toggle-group>.toggle-on.btn-xs{padding-right:.8rem}.toggle>.toggle-group>.toggle-off.btn-xs{padding-left:.8rem}
/*# sourceMappingURL=bootstrap5-toggle.min.css.map */

16377
public/css/bootstrap.css vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

42
public/css/bootstrap4-toggle.min.css vendored Normal file
View file

@ -0,0 +1,42 @@
/*\
|*| ========================================================================
|*| Bootstrap Toggle: bootstrap4-toggle.css v3.5.0
|*| https://gitbrent.github.io/bootstrap-toggle/
|*| ========================================================================
|*| Copyright 2018-2019 Brent Ely
|*| Licensed under MIT
|*| ========================================================================
\*/
.btn-group-xs>.btn,.btn-xs{padding:.35rem .4rem .25rem;font-size:.875rem;line-height:.5;border-radius:.2rem}
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-1.25rem;margin-right:.35rem}
.toggle{position:relative;overflow:hidden}
.toggle.btn.btn-light,.toggle.btn.btn-outline-light{border-color:rgba(0,0,0,.15)}
.toggle input[type=checkbox]{display:none}
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
.toggle-group label,.toggle-group span{cursor:pointer}
.toggle.off .toggle-group{left:-100%}
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0;box-shadow:none}
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px;background-color:#fff}
.toggle.btn-outline-primary .toggle-handle{background-color:var(--primary);border-color:var(--primary)}
.toggle.btn-outline-secondary .toggle-handle{background-color:var(--secondary);border-color:var(--secondary)}
.toggle.btn-outline-success .toggle-handle{background-color:var(--success);border-color:var(--success)}
.toggle.btn-outline-danger .toggle-handle{background-color:var(--danger);border-color:var(--danger)}
.toggle.btn-outline-warning .toggle-handle{background-color:var(--warning);border-color:var(--warning)}
.toggle.btn-outline-info .toggle-handle{background-color:var(--info);border-color:var(--info)}
.toggle.btn-outline-light .toggle-handle{background-color:var(--light);border-color:var(--light)}
.toggle.btn-outline-dark .toggle-handle{background-color:var(--dark);border-color:var(--dark)}
.toggle[class*=btn-outline]:hover .toggle-handle{background-color:var(--light);opacity:.5}
.toggle.btn{min-width:3.7rem;min-height:2.15rem}
.toggle-on.btn{padding-right:1.5rem}
.toggle-off.btn{padding-left:1.5rem}
.toggle.btn-lg{min-width:5rem;min-height:2.815rem}
.toggle-on.btn-lg{padding-right:2rem}
.toggle-off.btn-lg{padding-left:2rem}
.toggle-handle.btn-lg{width:2.5rem}
.toggle.btn-sm{min-width:3.125rem;min-height:1.938rem}
.toggle-on.btn-sm{padding-right:1rem}
.toggle-off.btn-sm{padding-left:1rem}
.toggle.btn-xs{min-width:2.19rem;min-height:1.375rem}
.toggle-on.btn-xs{padding-right:.8rem}
.toggle-off.btn-xs{padding-left:.8rem}

View file

@ -1,9 +1,27 @@
<?php <?php
use App\Kernel; use App\Kernel;
use Symfony\Component\Debug\Debug;
use Symfony\Component\HttpFoundation\Request;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; require dirname(__DIR__).'/config/bootstrap.php';
return function (array $context) { if ($_SERVER['APP_DEBUG']) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); umask(0000);
};
Debug::enable();
}
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? $_ENV['TRUSTED_PROXIES'] ?? false) {
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? $_ENV['TRUSTED_HOSTS'] ?? false) {
Request::setTrustedHosts([$trustedHosts]);
}
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8154
public/js/bootstrap.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11
public/js/bootstrap4-toggle.min.js vendored Normal file
View file

@ -0,0 +1,11 @@
/*\
|*| ========================================================================
|*| Bootstrap Toggle: bootstrap4-toggle.js v3.5.0
|*| https://gitbrent.github.io/bootstrap-toggle/
|*| ========================================================================
|*| Copyright 2018-2019 Brent Ely
|*| Licensed under MIT
|*| ========================================================================
\*/
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="3.5.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"light",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size||"lg"===this.options.size?"btn-lg":"small"===this.options.size||"sm"===this.options.size?"btn-sm":"mini"===this.options.size||"xs"===this.options.size?"btn-xs":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b),e=a('<span class="toggle-handle btn btn-light">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle" role="button">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){if(this.$element.prop("disabled"))return!1;this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),a||this.trigger()},c.prototype.off=function(a){if(this.$element.prop("disabled"))return!1;this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),a||this.trigger()},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){a(this).find("input[type=checkbox]").bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
//# sourceMappingURL=bootstrap4-toggle.min.js.map

View file

@ -1400,14 +1400,13 @@ document = window.document || {};
self.editor.html(self.content = ''); self.editor.html(self.content = '');
} }
source[sourceValFunc](self.getText()); source[sourceValFunc](self.getText());
var count = 0; let inputText;
$('.emojionearea-editor').each(function() { inputText = self.getText();
var currentElement = $(this); inputText = inputText
count += currentElement.text() .replace(/(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/ig, '$1@$3')
.replace(/(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/ig, '$1@$3') .replace(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/g, 'xxxxxxxxxxxxxxxxxxxxxxx');
.replace(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/g, 'xxxxxxxxxxxxxxxxxxxxxxx').length;
}); $("#count").text(inputText.length);
$("#count").text(count);
}); });
if (options.shortcuts) { if (options.shortcuts) {
self.on("@keydown", function(_, e) { self.on("@keydown", function(_, e) {
@ -1457,11 +1456,12 @@ document = window.document || {};
id: css_class, id: css_class,
match: /\B((:[\-+\w]*)|(@[\-+\w]*)|(#[\-+\w]*))$/, match: /\B((:[\-+\w]*)|(@[\-+\w]*)|(#[\-+\w]*))$/,
search: function (term, callback) { search: function (term, callback) {
if (term.startsWith(":")) { if (term.startsWith(":")) {
callback($.map(map, function (emoji) { callback($.map(map, function (emoji) {
return emoji.indexOf(term) === 0 ? emoji : null; return emoji.indexOf(term) === 0 ? emoji : null;
})); }));
} else if (term.startsWith("@") && term.substring(1).length > 1){ } else if (term.startsWith("@")){
$.ajax({ $.ajax({
url: "https://"+$('#data_api').attr('data-instance')+"/api/v2/search?type=accounts&q="+term.substring(1), url: "https://"+$('#data_api').attr('data-instance')+"/api/v2/search?type=accounts&q="+term.substring(1),
headers: {"Authorization": $('#data_api').attr('data-token')}, headers: {"Authorization": $('#data_api').attr('data-token')},
@ -1471,7 +1471,7 @@ document = window.document || {};
return value; return value;
})); }));
}); });
}else if (term.startsWith("#") && term.substring(1).length > 1){ }else if (term.startsWith("#")){
$.ajax({ $.ajax({
url: "https://"+$('#data_api').attr('data-instance')+"/api/v2/search?type=hashtags&q="+term.substring(1), url: "https://"+$('#data_api').attr('data-instance')+"/api/v2/search?type=hashtags&q="+term.substring(1),
headers: {"Authorization": $('#data_api').attr('data-token')}, headers: {"Authorization": $('#data_api').attr('data-token')},
@ -1481,10 +1481,6 @@ document = window.document || {};
return value; return value;
})); }));
}); });
} else {
callback($.map(map, function () {
return null;
}));
} }
}, },
template: function (value) { template: function (value) {
@ -1504,6 +1500,7 @@ document = window.document || {};
}else if (typeof value.name != 'undefined') { }else if (typeof value.name != 'undefined') {
return "#"+value.name+ "&nbsp;"; return "#"+value.name+ "&nbsp;";
}else{ }else{
return shortnameTo(value, self.emojiTemplate); return shortnameTo(value, self.emojiTemplate);
} }
}, },

View file

@ -1,4 +1,8 @@
<?php <?php /** @noinspection PhpUndefinedClassInspection */
/** @noinspection PhpDocSignatureInspection */
/** @noinspection PhpUnused */
/** @noinspection DuplicatedCode */
/** @noinspection PhpTranslationKeyInspection */
/** /**
* Created by fediplan. * Created by fediplan.
@ -11,39 +15,34 @@ namespace App\Controller;
use App\Form\ComposeType; use App\Form\ComposeType;
use App\Form\ConnectMastodonAccountFlow; use App\Form\ConnectMastodonAccountFlow;
use App\Security\MastodonAccount;
use App\Services\Mastodon_api; use App\Services\Mastodon_api;
use App\SocialEntity\Client; use App\SocialEntity\Client;
use App\SocialEntity\Compose; use App\SocialEntity\Compose;
use App\SocialEntity\MastodonAccount;
use App\SocialEntity\PollOption; use App\SocialEntity\PollOption;
use DateTime; use DateTime;
use DateTimeZone; use DateTimeZone;
use Exception; use Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
use \Symfony\Component\HttpFoundation\RedirectResponse;
use \Symfony\Component\HttpFoundation\Response;
class FediPlanController extends AbstractController class FediPlanController extends AbstractController
{ {
#[Route( /**
'/{_locale}', * @Route("/{_locale}",name="index", defaults={"_locale"="en"}, requirements={"_locale": "%allowed_language%"})
name: 'index', */
requirements: ['_locale' => '%allowed_language%'], public function indexAction(Request $request, AuthorizationCheckerInterface $authorizationChecker, ConnectMastodonAccountFlow $flow, Mastodon_api $mastodon_api, TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher)
defaults: ['_locale'=>'en']
)]
public function index(Request $request, AuthorizationCheckerInterface $authorizationChecker, ConnectMastodonAccountFlow $flow, Mastodon_api $mastodon_api, TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher): RedirectResponse|Response
{ {
if ($authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY')) { if ($authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY')) {
@ -73,11 +72,15 @@ class FediPlanController extends AbstractController
// form for the next step // form for the next step
$mastodon_api->set_client($createApp['response']['client_id'], $createApp['response']['client_secret']); $mastodon_api->set_client($createApp['response']['client_id'], $createApp['response']['client_secret']);
$urlToMastodon = $mastodon_api->getAuthorizationUrl(); $urlToMastodon = $mastodon_api->getAuthorizationUrl();
$flow->saveCurrentStepData($form); if (isset($createApp['error'])) {
$client_id = $createApp['response']['client_id']; $form->get('host')->addError(new FormError($translator->trans('error.instance.mastodon_oauth_url', [], 'fediplan', 'en')));
$client_secret = $createApp['response']['client_secret']; } else {
$flow->nextStep(); $flow->saveCurrentStepData($form);
$form = $flow->createForm(); $client_id = $createApp['response']['client_id'];
$client_secret = $createApp['response']['client_secret'];
$flow->nextStep();
$form = $flow->createForm();
}
} }
} }
@ -99,23 +102,14 @@ class FediPlanController extends AbstractController
if (isset($accountReply['error'])) { if (isset($accountReply['error'])) {
$form->get('code')->addError(new FormError($translator->trans('error.instance.mastodon_account', [], 'fediplan', 'en'))); $form->get('code')->addError(new FormError($translator->trans('error.instance.mastodon_account', [], 'fediplan', 'en')));
} else { } else {
$account = $mastodon_api->getSingleAccount($accountReply['response']); $Account = $mastodon_api->getSingleAccount($accountReply['response']);
$instanceReply = $mastodon_api->get_instance(); $Account->setInstance($host);
$instance = $mastodon_api->getInstanceConfiguration($instanceReply['response']); $Account->setToken($token_type . " " . $access_token);
$session = $request->getSession(); $token = new UsernamePasswordToken($Account, null, 'main', array('ROLE_USER'));
$session->set("instance",$instance); $this->get('security.token_storage')->setToken($token);
$account->setInstance($host); $event = new InteractiveLoginEvent($request, $token);
$account->setToken($token_type . " " . $access_token); $eventDispatcher->dispatch($event, "security.interactive_login");
$token = new UsernamePasswordToken($account, 'main', array('ROLE_USER')); return $this->redirectToRoute('schedule');
try {
$this->container->get('security.token_storage')->setToken($token);
$event = new InteractiveLoginEvent($request, $token);
$eventDispatcher->dispatch($event, "security.interactive_login");
return $this->redirectToRoute('schedule');
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
$form->get('code')->addError(new FormError($translator->trans('error.instance.mastodon_account', [], 'fediplan', 'en')));
}
} }
} }
} }
@ -134,31 +128,27 @@ class FediPlanController extends AbstractController
} }
#[Route( /**
'/{_locale}/schedule', * @Route("/{_locale}/schedule", name="schedule", defaults={"_locale"="en"}, requirements={"_locale": "%allowed_language%"})
name: 'schedule', */
requirements: ['_locale' => '%allowed_language%'], public function schedule(Request $request, Mastodon_api $mastodon_api, TranslatorInterface $translator)
defaults: ['_locale'=>'en']
)]
public function schedule(Request $request, Mastodon_api $mastodon_api, TranslatorInterface $translator): Response
{ {
$compose = new Compose(); $compose = new Compose();
$pollOption1 = new PollOption(); $pollOption1 = new PollOption();
$pollOption1->setTitle(""); $pollOption1->setTitle("");
$options = $compose->getPollOptions(); $compose->getPollOptions()->add($pollOption1);
$options[] = $pollOption1;
$pollOption2 = new PollOption(); $pollOption2 = new PollOption();
$pollOption2->setTitle(""); $pollOption2->setTitle("");
$options[] = $pollOption2; $compose->getPollOptions()->add($pollOption2);
$compose->setPollOptions($options); $form = $this->createForm(ComposeType::class, $compose, ['user' => $this->getUser()]);
$user = $this->getUser();
$form = $this->createForm(ComposeType::class, $compose, ['user' => $user]);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
/** @var $data Compose */ /** @var $data Compose */
$data = $form->getData(); $data = $form->getData();
/* @var $user MastodonAccount */
$user = $this->getUser();
$mastodon_api->set_url("https://" . $user->getInstance()); $mastodon_api->set_url("https://" . $user->getInstance());
$token = explode(" ", $user->getToken())[1]; $token = explode(" ", $user->getToken())[1];
$type = explode(" ", $user->getToken())[0]; $type = explode(" ", $user->getToken())[0];
@ -167,7 +157,8 @@ class FediPlanController extends AbstractController
//Update media description and store their id //Update media description and store their id
foreach ($_POST as $key => $value) { foreach ($_POST as $key => $value) {
if ($key != "compose") { if ($key != "compose") {
if (str_contains($key, 'media_id_')) {
if (strpos($key, 'media_id_') !== false) {
$mediaId = $value; $mediaId = $value;
$description = $_POST['media_description_' . $mediaId]; $description = $_POST['media_description_' . $mediaId];
@ -191,12 +182,7 @@ class FediPlanController extends AbstractController
} }
$params['sensitive'] = ($data->getSensitive() == null || !$data->getSensitive()) ? false : true; $params['sensitive'] = ($data->getSensitive() == null || !$data->getSensitive()) ? false : true;
if($data->getAttachPoll() > 0) { $pollOptions = $data->getPollOptions();
$pollOptions = $data->getPollOptions();
} else{
$pollOptions = array();
}
$pollExpiresAt = $data->getPollExpiresAt(); $pollExpiresAt = $data->getPollExpiresAt();
$isPollMultiple = $data->isPollMultiple(); $isPollMultiple = $data->isPollMultiple();
if (count($pollOptions) > 0) { if (count($pollOptions) > 0) {
@ -241,12 +227,10 @@ class FediPlanController extends AbstractController
$compose = new Compose(); $compose = new Compose();
$pollOption1 = new PollOption(); $pollOption1 = new PollOption();
$pollOption1->setTitle(""); $pollOption1->setTitle("");
$options = $compose->getPollOptions(); $compose->getPollOptions()->add($pollOption1);
$options[] = $pollOption1;
$pollOption2 = new PollOption(); $pollOption2 = new PollOption();
$pollOption2->setTitle(""); $pollOption2->setTitle("");
$options[] = $pollOption2; $compose->getPollOptions()->add($pollOption2);
$compose->setPollOptions($options);
$session->getFlashBag()->add( $session->getFlashBag()->add(
'Success', 'Success',
$translator->trans('common.schedule_success', [], 'fediplan', 'en') $translator->trans('common.schedule_success', [], 'fediplan', 'en')
@ -254,9 +238,8 @@ class FediPlanController extends AbstractController
$form = $this->createForm(ComposeType::class, $compose, ['user' => $this->getUser()]); $form = $this->createForm(ComposeType::class, $compose, ['user' => $this->getUser()]);
} }
} }
/** @var $user MastodonAccount */
$user = $this->getUser(); $user = $this->getUser();
/** @var $user MastodonAccount */
return $this->render("fediplan/schedule.html.twig", [ return $this->render("fediplan/schedule.html.twig", [
'form' => $form->createView(), 'form' => $form->createView(),
@ -266,53 +249,42 @@ class FediPlanController extends AbstractController
} }
#[Route(
'/{_locale}/scheduled', /**
name: 'scheduled', * @Route("/{_locale}/scheduled", name="scheduled", defaults={"_locale"="en"}, requirements={"_locale": "%allowed_language%"})
requirements: ['_locale' => '%allowed_language%'], */
defaults: ['_locale'=>'en'] public function scheduled()
)]
public function scheduled(): Response
{ {
$user = $this->getUser(); return $this->render("fediplan/scheduled.html.twig");
return $this->render("fediplan/scheduled.html.twig", [ 'instance' => $user->getInstance(),]);
} }
#[Route( /**
'/{_locale}/scheduled/messages/{max_id}', * @Route("/{_locale}/scheduled/messages/{max_id}", options={"expose"=true}, name="load_more")
name: 'load_more', */
options: ['expose' => true] public function loadMoreAction(Mastodon_api $mastodon_api, string $max_id = null)
)]
public function loadMoreAction(Mastodon_api $mastodon_api, ?string $max_id = null , int $limit = 10): JsonResponse
{ {
/** @var $user MastodonAccount */
$user = $this->getUser(); $user = $this->getUser();
$mastodon_api->set_url("https://" . $user->getInstance()); $mastodon_api->set_url("https://" . $user->getInstance());
$token = explode(" ", $user->getToken())[1]; $token = explode(" ", $user->getToken())[1];
$type = explode(" ", $user->getToken())[0]; $type = explode(" ", $user->getToken())[0];
$mastodon_api->set_token($token, $type); $mastodon_api->set_token($token, $type);
$params = []; $params = [];
$params['limit'] = $limit;
if ($max_id != null) { if ($max_id != null) {
$params['max_id'] = $max_id; $params['max_id'] = $max_id;
} }
$scheduled_reply = $mastodon_api->get_scheduled($params); $scheduled_reply = $mastodon_api->get_scheduled($params);
$statuses = $mastodon_api->getScheduledStatuses($scheduled_reply['response'], $user); $statuses = $mastodon_api->getScheduledStatuses($scheduled_reply['response'], $this->getUser());
$data['max_id'] = $statuses[count($statuses)-1]->getId(); $data['max_id'] = $scheduled_reply['max_id'];
$data['html'] = $this->renderView('fediplan/Ajax/layout.html.twig', ['statuses' => $statuses]); $data['html'] = $this->renderView('fediplan/Ajax/layout.html.twig', ['statuses' => $statuses]);
return new JsonResponse($data); return new JsonResponse($data);
} }
#[Route( /**
'/{_locale}/scheduled/delete/messages/{id}', * @Route("/{_locale}/scheduled/delete/messages/{id}", options={"expose"=true}, name="delete_message", methods={"POST"}, defaults={"_locale"="en"}, requirements={"_locale": "%allowed_language%"})
name: 'delete_message', */
requirements: ['_locale' => '%allowed_language%'], public function deleteMessage(Mastodon_api $mastodon_api, string $id = null)
options: ['expose' => true],
defaults: ['_locale'=>'en'],
methods: ['POST']
)]
public function deleteMessage(Mastodon_api $mastodon_api, ?string $id = null): JsonResponse
{ {
$user = $this->getUser(); $user = $this->getUser();
$mastodon_api->set_url("https://" . $user->getInstance()); $mastodon_api->set_url("https://" . $user->getInstance());
@ -323,23 +295,19 @@ class FediPlanController extends AbstractController
return new JsonResponse($response); return new JsonResponse($response);
} }
/**
#[Route( * @Route("/about",defaults={"_locale"="en"})
'/{_locale}/about', * @Route("/{_locale}/about", name="about", defaults={"_locale":"en"}, requirements={"_locale": "%allowed_language%"})
name: 'about', */
requirements: ['_locale' => '%allowed_language%'], public function about()
defaults: ['_locale'=>'en']
)]
public function about(): Response
{ {
return $this->render("fediplan/about.html.twig"); return $this->render("fediplan/about.html.twig");
} }
#[Route( /**
'/logout', * @Route("/logout", name="logout")
name: 'logout' */
)] public function logout()
public function logout(): Response
{ {
return $this->render("fediplan/index.html.twig"); return $this->render("fediplan/index.html.twig");
} }

View file

@ -15,14 +15,14 @@ use Symfony\Component\HttpKernel\KernelEvents;
class LocaleSubscriber implements EventSubscriberInterface class LocaleSubscriber implements EventSubscriberInterface
{ {
private string $defaultLocale; private $defaultLocale;
public function __construct($defaultLocale = 'en') public function __construct($defaultLocale = 'en')
{ {
$this->defaultLocale = $defaultLocale; $this->defaultLocale = $defaultLocale;
} }
public static function getSubscribedEvents(): array public static function getSubscribedEvents()
{ {
return [ return [
// must be registered before (i.e. with a higher priority than) the default Locale listener // must be registered before (i.e. with a higher priority than) the default Locale listener
@ -30,7 +30,7 @@ class LocaleSubscriber implements EventSubscriberInterface
]; ];
} }
public function onKernelRequest(RequestEvent $event): void public function onKernelRequest(RequestEvent $event)
{ {
$request = $event->getRequest(); $request = $event->getRequest();
if (!$request->hasPreviousSession()) { if (!$request->hasPreviousSession()) {

View file

@ -10,29 +10,28 @@
namespace App\Form; namespace App\Form;
use App\Security\MastodonAccount;
use App\SocialEntity\Compose; use App\SocialEntity\Compose;
use App\SocialEntity\MastodonAccount;
use DateTime; use DateTime;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TimezoneType; use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\Translator;
class ComposeType extends AbstractType class ComposeType extends AbstractType
{ {
private Security $securityContext; private $securityContext;
private $translator; private $translator;
public function __construct(Security $securityContext, Translator $translator) public function __construct(Security $securityContext, Translator $translator)
@ -41,7 +40,7 @@ class ComposeType extends AbstractType
$this->translator = $translator; $this->translator = $translator;
} }
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options)
{ {
/**@var $user MastodonAccount */ /**@var $user MastodonAccount */
$user = $options['user']; $user = $options['user'];
@ -77,8 +76,6 @@ class ComposeType extends AbstractType
'data' => $user->getDefaultVisibility(), 'data' => $user->getDefaultVisibility(),
'label' => 'page.schedule.form.visibility', 'label' => 'page.schedule.form.visibility',
'translation_domain' => 'fediplan']); 'translation_domain' => 'fediplan']);
$builder->add('attach_poll', HiddenType::class, ['required' => true, 'empty_data' => 0]);
$builder->add('timeZone', TimezoneType::class, $builder->add('timeZone', TimezoneType::class,
[ [
'label' => 'page.schedule.form.timeZone', 'label' => 'page.schedule.form.timeZone',
@ -126,7 +123,7 @@ class ComposeType extends AbstractType
} }
public function configureOptions(OptionsResolver $resolver): void public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'data_class' => Compose::class, 'data_class' => Compose::class,

View file

@ -14,7 +14,7 @@ use Craue\FormFlowBundle\Form\FormFlow;
class ConnectMastodonAccountFlow extends FormFlow class ConnectMastodonAccountFlow extends FormFlow
{ {
protected function loadStepsConfig(): array protected function loadStepsConfig()
{ {
return [ return [
[ [

View file

@ -17,7 +17,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class ConnectMastodonAccountType extends AbstractType class ConnectMastodonAccountType extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options)
{ {
switch ($options['flow_step']) { switch ($options['flow_step']) {
case 1: case 1:
@ -38,12 +38,12 @@ class ConnectMastodonAccountType extends AbstractType
} }
} }
public function getBlockPrefix(): string public function getBlockPrefix()
{ {
return 'addMastodonAccount'; return 'addMastodonAccount';
} }
public function configureOptions(OptionsResolver $resolver): void public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'validation_groups' => ['registration'], 'validation_groups' => ['registration'],

View file

@ -7,42 +7,36 @@
namespace App\Form; namespace App\Form;
use App\SocialEntity\Instance;
use App\SocialEntity\PollOption; use App\SocialEntity\PollOption;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;
class PollOptionType extends AbstractType class PollOptionType extends AbstractType
{ {
private Security $securityContext; private $securityContext;
private Instance $instance;
public function __construct(Security $securityContext, RequestStack $requestStack) public function __construct(Security $securityContext)
{ {
$this->securityContext = $securityContext; $this->securityContext = $securityContext;
$this->instance = $requestStack->getSession()->get('instance');
} }
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$max_char = $this->instance->getConfiguration()->getPolls()->getMaxCharactersPerOption();
$builder->add('title', TextType::class, $builder->add('title', TextType::class,
[ [
'required' => false, 'required' => false,
'attr' => ['class' => 'form-control', 'maxlength' => $max_char], 'attr' => ['class' => 'form-control'],
'label' => 'page.schedule.form.poll_item', 'label' => 'page.schedule.form.poll_item',
]); ]);
} }
public function configureOptions(OptionsResolver $resolver): void public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'data_class' => PollOption::class, 'data_class' => PollOption::class,

View file

@ -3,9 +3,52 @@
namespace App; namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
use function dirname;
class Kernel extends BaseKernel class Kernel extends BaseKernel
{ {
use MicroKernelTrait; use MicroKernelTrait;
private const CONFIG_EXTS = '.{php,xml,yaml,yml}';
public function registerBundles(): iterable
{
$contents = require $this->getProjectDir() . '/config/bundles.php';
foreach ($contents as $class => $envs) {
if ($envs[$this->environment] ?? $envs['all'] ?? false) {
yield new $class();
}
}
}
public function getProjectDir(): string
{
return dirname(__DIR__);
}
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
$container->addResource(new FileResource($this->getProjectDir() . '/config/bundles.php'));
$container->setParameter('container.dumper.inline_class_loader', true);
$confDir = $this->getProjectDir() . '/config';
$loader->load($confDir . '/{packages}/*' . self::CONFIG_EXTS, 'glob');
$loader->load($confDir . '/{packages}/' . $this->environment . '/**/*' . self::CONFIG_EXTS, 'glob');
$loader->load($confDir . '/{services}' . self::CONFIG_EXTS, 'glob');
$loader->load($confDir . '/{services}_' . $this->environment . self::CONFIG_EXTS, 'glob');
}
protected function configureRoutes(RouteCollectionBuilder $routes): void
{
$confDir = $this->getProjectDir() . '/config';
$routes->import($confDir . '/{routes}/' . $this->environment . '/**/*' . self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir . '/{routes}/*' . self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir . '/{routes}' . self::CONFIG_EXTS, '/', 'glob');
}
} }

View file

@ -1,79 +0,0 @@
<?php
namespace App\Security;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserProvider implements UserProviderInterface, PasswordUpgraderInterface
{
/**
* Symfony calls this method if you use features like switch_user
* or remember_me.
*
* If you're not using these features, you do not need to implement
* this method.
*
* @throws UserNotFoundException if the user is not found
*/
public function loadUserByIdentifier($identifier): UserInterface
{
// Load a User object from your data source or throw UserNotFoundException.
// The $identifier argument may not actually be a username:
// it is whatever value is being returned by the getUserIdentifier()
// method in your User class.
throw new \Exception('TODO: fill in loadUserByIdentifier() inside '.__FILE__);
}
/**
* @deprecated since Symfony 5.3, loadUserByIdentifier() is used instead
*/
public function loadUserByUsername($username): UserInterface
{
return $this->loadUserByIdentifier($username);
}
/**
* Refreshes the user after being reloaded from the session.
*
* When a user is logged in, at the beginning of each request, the
* User object is loaded from the session and then this method is
* called. Your job is to make sure the user's data is still fresh by,
* for example, re-querying for fresh User data.
*
* If your firewall is "stateless: true" (for a pure API), this
* method is not called.
*/
public function refreshUser(UserInterface $user): UserInterface
{
if (!$user instanceof MastodonAccount) {
throw new UnsupportedUserException(sprintf('Invalid user class "%s".', $user::class));
}
// Return a User object after making sure its data is "fresh".
// Or throw a UsernameNotFoundException if the user no longer exists.
return $user;
}
/**
* Tells Symfony to use this provider for this User class.
*/
public function supportsClass(string $class): bool
{
return MastodonAccount::class === $class || is_subclass_of($class, MastodonAccount::class);
}
/**
* Upgrades the hashed password of a user, typically for using a better hash algorithm.
*/
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
// TODO: when hashed passwords are in use, this method should:
// 1. persist the new password in the user storage
// 2. update the $user object with $user->setPassword($newHashedPassword);
}
}

View file

@ -286,21 +286,52 @@ class Curl
* *
* @param string $url The url to make the post request * @param string $url The url to make the post request
* @param array $data Post data to pass to the url * @param array $data Post data to pass to the url
* @param bool $payload
* @return self * @return self
*/ */
public function post($url, $data = array()) public function post($url, $data = array(), $payload = false)
{ {
$fields_string = http_build_query($data); if (!empty($data)) {
$payload = json_encode( $data ); if ($payload === false) {
// Check if the url has not already been modified
$url .= strpos($url, '?') !== false ? '&' : '?';
$url .= http_build_query($data);
} else {
$this->preparePayload($data);
}
}
$this->setOpt(CURLOPT_URL, $url); $this->setOpt(CURLOPT_URL, $url);
$this->setOpt(CURLOPT_RETURNTRANSFER, true);
$this->setOpt(CURLOPT_POST, true);
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'POST'); $this->setOpt(CURLOPT_CUSTOMREQUEST, 'POST');
$this->setOpt(CURLOPT_POSTFIELDS, $payload);
$this->exec(); $this->exec();
return $this; return $this;
} }
/**
* @param array|object|string $data
*/
protected function preparePayload($data)
{
$this->setOpt(CURLOPT_POST, true);
if (is_array($data) || is_object($data)) {
$skip = false;
foreach ($data as $key => $value) {
// If a value is an instance of CurlFile skip the http_build_query
// see issue https://github.com/php-mod/curl/issues/46
// suggestion from: https://stackoverflow.com/a/36603038/4611030
if ($value instanceof CurlFile) {
$skip = true;
}
}
if (!$skip) {
$data = http_build_query($data);
}
}
$this->setOpt(CURLOPT_POSTFIELDS, $data);
}
/** /**
* Make a put request with optional data. * Make a put request with optional data.
@ -309,16 +340,21 @@ class Curl
* *
* @param string $url The url to make the put request * @param string $url The url to make the put request
* @param array $data Optional data to pass to the $url * @param array $data Optional data to pass to the $url
* @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
* @return self * @return self
*/ */
public function put($url, $data = array()) public function put($url, $data = array(), $payload = false)
{ {
$fields_string = http_build_query($data); if (!empty($data)) {
if ($payload === false) {
$url .= '?' . http_build_query($data);
} else {
$this->preparePayload($data);
}
}
$this->setOpt(CURLOPT_URL, $url); $this->setOpt(CURLOPT_URL, $url);
$this->setOpt(CURLOPT_POST, 1);
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'PUT'); $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PUT');
$this->setOpt(CURLOPT_POSTFIELDS, $fields_string);
$this->exec(); $this->exec();
return $this; return $this;
} }
@ -330,16 +366,21 @@ class Curl
* *
* @param string $url The url to make the patch request * @param string $url The url to make the patch request
* @param array $data Optional data to pass to the $url * @param array $data Optional data to pass to the $url
* @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
* @return self * @return self
*/ */
public function patch($url, $data = array()) public function patch($url, $data = array(), $payload = false)
{ {
$fields_string = http_build_query($data); if (!empty($data)) {
if ($payload === false) {
$url .= '?' . http_build_query($data);
} else {
$this->preparePayload($data);
}
}
$this->setOpt(CURLOPT_URL, $url); $this->setOpt(CURLOPT_URL, $url);
$this->setOpt(CURLOPT_POST, 1);
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH'); $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH');
$this->setOpt(CURLOPT_POSTFIELDS, $fields_string);
$this->exec(); $this->exec();
return $this; return $this;
} }
@ -351,16 +392,21 @@ class Curl
* *
* @param string $url The url to make the delete request * @param string $url The url to make the delete request
* @param array $data Optional data to pass to the $url * @param array $data Optional data to pass to the $url
* @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
* @return self * @return self
*/ */
public function delete($url, $data = array()) public function delete($url, $data = array(), $payload = false)
{ {
$fields_string = http_build_query($data); if (!empty($data)) {
if ($payload === false) {
$url .= '?' . http_build_query($data);
} else {
$this->preparePayload($data);
}
}
$this->setOpt(CURLOPT_URL, $url); $this->setOpt(CURLOPT_URL, $url);
$this->setOpt(CURLOPT_POST, 1);
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE'); $this->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
$this->setOpt(CURLOPT_POSTFIELDS, $fields_string);
$this->exec(); $this->exec();
return $this; return $this;
} }

View file

@ -11,22 +11,17 @@
namespace App\Services; namespace App\Services;
use App\Security\MastodonAccount;
use App\Services\Curl as Curl; use App\Services\Curl as Curl;
use App\SocialEntity\Application; use App\SocialEntity\Application;
use App\SocialEntity\Attachment; use App\SocialEntity\Attachment;
use App\SocialEntity\Configuration;
use App\SocialEntity\CustomField; use App\SocialEntity\CustomField;
use App\SocialEntity\Emoji; use App\SocialEntity\Emoji;
use App\SocialEntity\Instance; use App\SocialEntity\MastodonAccount;
use App\SocialEntity\MediaAttachments;
use App\SocialEntity\Mention; use App\SocialEntity\Mention;
use App\SocialEntity\Notification; use App\SocialEntity\Notification;
use App\SocialEntity\Poll; use App\SocialEntity\Poll;
use App\SocialEntity\PollOption; use App\SocialEntity\PollOption;
use App\SocialEntity\Polls;
use App\SocialEntity\Status; use App\SocialEntity\Status;
use App\SocialEntity\Statuses;
use App\SocialEntity\Tag; use App\SocialEntity\Tag;
use CURLFile; use CURLFile;
use DateTime; use DateTime;
@ -71,7 +66,7 @@ class Mastodon_api
* *
* @param string $path * @param string $path
*/ */
public function set_url(string $path): void public function set_url($path)
{ {
$this->mastodon_url = $path; $this->mastodon_url = $path;
} }
@ -82,7 +77,7 @@ class Mastodon_api
* @param string $id * @param string $id
* @param string $secret * @param string $secret
*/ */
public function set_client(string $id, string $secret): void public function set_client($id, $secret)
{ {
$this->client_id = $id; $this->client_id = $id;
$this->client_secret = $secret; $this->client_secret = $secret;
@ -94,7 +89,7 @@ class Mastodon_api
* @param string $token * @param string $token
* @param string $type * @param string $type
*/ */
public function set_token(string $token, string $type): void public function set_token($token, $type)
{ {
$this->token['access_token'] = $token; $this->token['access_token'] = $token;
$this->token['token_type'] = $type; $this->token['token_type'] = $type;
@ -105,7 +100,7 @@ class Mastodon_api
* *
* @param array $scopes read / write / follow * @param array $scopes read / write / follow
*/ */
public function set_scopes(array $scopes): void public function set_scopes($scopes)
{ {
$this->scopes = $scopes; $this->scopes = $scopes;
} }
@ -124,7 +119,7 @@ class Mastodon_api
* string $response['client_id'] * string $response['client_id']
* string $response['client_secret'] * string $response['client_secret']
*/ */
public function create_app(string $client_name, array $scopes = array(), string $redirect_uris = '', string $website = ''): array public function create_app($client_name, $scopes = array(), $redirect_uris = '', $website = '')
{ {
$parameters = array(); $parameters = array();
@ -167,7 +162,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
private function _post(string $url, array $parameters = array()): array private function _post($url, $parameters = array())
{ {
$params["method"] = "POST"; $params["method"] = "POST";
@ -190,33 +185,71 @@ class Mastodon_api
* *
* @return array $data * @return array $data
*/ */
public function get_content_remote(string $url, array $parameters = array()): array public function get_content_remote($url, $parameters = array())
{ {
$data = array(); $data = array();
// set USERAGENT // set USERAGENT
$parameters['headers']['User-Agent'] = 'Mozilla/5.0 (X11; Linux i686; rv:126.0) Gecko/20100101 Firefox/126.0'; if (isset($_SERVER['HTTP_USER_AGENT'])) {
$parameters['headers']['User-Agent'] = $_SERVER['HTTP_USER_AGENT'];
} else {
// default IE11
$parameters['headers']['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko';
}
$curl = new Curl(); $curl = new Curl();
$response = null; $response = null;
if (isset($parameters["method"]) && $parameters['method'] == "POST") {
$parameters['headers']['content-type'] = 'application/json';
}
foreach ($parameters['headers'] as $key => $value) { foreach ($parameters['headers'] as $key => $value) {
$curl->setHeader($key, $value); $curl->setHeader($key, $value);
} }
if (isset($parameters["method"]) && $parameters['method'] == "POST") {
$response = $curl->post($url, $parameters['body']); //Special treatment for sending media when editing profile
}else if (isset($parameters["method"]) && $parameters['method'] == "GET") { if (isset($parameters['body']['media'])) {
$response = $curl->get($url, $parameters['body']); $fields = [$parameters['body']['media']['name'] => new CURLFile($parameters['body']['media']['path'], $parameters['body']['media']['mimetype'], $parameters['body']['media']['filename'])];
}else if (isset($parameters["method"]) && $parameters['method'] == "PUT") { $curl->setOpt(CURLOPT_POSTFIELDS, $fields);
$response = $curl->put($url, $parameters['body']);
}else if (isset($parameters["method"]) && $parameters['method'] == "PATCH") {
$response = $curl->patch($url, $parameters['body']);
}else if (isset($parameters["method"]) && $parameters['method'] == "DELETE") {
$response = $curl->delete($url);
} }
// Since Curl does not let us upload media_ids as we wish, we had to pass it through the url, directly.
if (isset($parameters['body']['media_ids'])) {
$url .= strpos($url, '?') !== false ? '' : '?';
foreach ($parameters['body']['media_ids'] as $key => $value) {
$url .= 'media_ids[]=' . (int)$value . '&';
}
$url = substr($url, 0, -1);
unset($parameters['body']['media_ids']);
}
if (isset($parameters['body']['poll']['options'])) {
$url .= strpos($url, '?') !== false ? '' : '?';
foreach ($parameters['body']['poll']['options'] as $key => $value) {
$url .= 'poll[options][]=' . urlencode($value) . '&';
}
$url = substr($url, 0, -1);
unset($parameters['body']['poll']['options']);
}
//Special treatment for filtering notifications
if (isset($parameters['body']['exclude_types[]']) && $parameters['method'] == "GET") {
$url .= "?";
foreach ($parameters['body']['exclude_types[]'] as $key => $value) {
$url .= "exclude_types[]=" . $value . "&";
}
if (isset($parameters['body']['max_id']))
$url .= "&max_id=" . $parameters['body']['max_id'];
$parameters['body'] = [];
}
if (isset($parameters["method"]) && $parameters['method'] == "POST")
$response = $curl->post($url, $parameters['body']);
else if (isset($parameters["method"]) && $parameters['method'] == "GET")
$response = $curl->get($url, $parameters['body']);
else if (isset($parameters["method"]) && $parameters['method'] == "PUT")
$response = $curl->put($url, $parameters['body']);
else if (isset($parameters["method"]) && $parameters['method'] == "PATCH")
$response = $curl->patch($url, $parameters['body']);
else if (isset($parameters["method"]) && $parameters['method'] == "DELETE")
$response = $curl->delete($url);
$min_id = null; $min_id = null;
$max_id = null; $max_id = null;
if ($response->response_headers) { if ($response->response_headers) {
@ -250,7 +283,7 @@ class Mastodon_api
$data['error'] = $response->error; $data['error'] = $response->error;
$data['error_code'] = $response->error_code; $data['error_code'] = $response->error_code;
$data['error_message'] = $response->error_message; $data['error_message'] = $response->error_message;
if ($response->response && isset(json_decode($response->response, true)['error'])) if ($response->response)
$data['error_message'] = json_decode($response->response, true)['error']; $data['error_message'] = json_decode($response->response, true)['error'];
} else { } else {
$data['response_headers'] = $response->response_headers; $data['response_headers'] = $response->response_headers;
@ -271,7 +304,7 @@ class Mastodon_api
* string $response['scope'] read * string $response['scope'] read
* int $response['created_at'] time * int $response['created_at'] time
*/ */
public function login(string $id, string $password): array public function login($id, $password)
{ {
$parameters = array(); $parameters = array();
$parameters['client_id'] = $this->client_id; $parameters['client_id'] = $this->client_id;
@ -307,7 +340,7 @@ class Mastodon_api
* string $response['scope'] read * string $response['scope'] read
* int $response['created_at'] time * int $response['created_at'] time
*/ */
public function loginAuthorization(string $code, string $redirect_uri = ''): array public function loginAuthorization($code, $redirect_uri = '')
{ {
$parameters = array(); $parameters = array();
$parameters['client_id'] = $this->client_id; $parameters['client_id'] = $this->client_id;
@ -334,7 +367,7 @@ class Mastodon_api
* *
* @return string $response Authorization code * @return string $response Authorization code
*/ */
public function getAuthorizationUrl(string $redirect_uri = ''): string public function getAuthorizationUrl($redirect_uri = '')
{ {
if (empty($redirect_uri)) if (empty($redirect_uri))
$redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'; $redirect_uri = 'urn:ietf:wg:oauth:2.0:oob';
@ -356,7 +389,7 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
* int $response['id'] * int $response['id']
@ -375,7 +408,7 @@ class Mastodon_api
* string $response['header'] A base64 encoded image to display as the user's header image * string $response['header'] A base64 encoded image to display as the user's header image
* string $response['header_static'] * string $response['header_static']
*/ */
public function accounts(string $id): array public function accounts($id)
{ {
return $this->_get('/api/v1/accounts/' . $id); return $this->_get('/api/v1/accounts/' . $id);
} }
@ -388,7 +421,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
private function _get(string $url, array $parameters = array()): array private function _get($url, $parameters = array())
{ {
$params["method"] = "GET"; $params["method"] = "GET";
@ -400,6 +433,7 @@ class Mastodon_api
} }
$params['body'] = $parameters; $params['body'] = $parameters;
$url = $this->mastodon_url . $url; $url = $this->mastodon_url . $url;
return $this->get_content_remote($url, $params); return $this->get_content_remote($url, $params);
} }
@ -410,7 +444,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function accounts_verify_credentials(): array public function accounts_verify_credentials()
{ {
return $this->_get('/api/v1/accounts/verify_credentials'); return $this->_get('/api/v1/accounts/verify_credentials');
} }
@ -428,7 +462,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function accounts_update_credentials($parameters): array public function accounts_update_credentials($parameters)
{ {
return $this->_patch('/api/v1/accounts/update_credentials', $parameters); return $this->_patch('/api/v1/accounts/update_credentials', $parameters);
} }
@ -441,7 +475,7 @@ class Mastodon_api
* *
* @return array $parameters * @return array $parameters
*/ */
private function _patch(string $url, array $parameters = array()): array private function _patch($url, $parameters = array())
{ {
$params["method"] = "PATCH"; $params["method"] = "PATCH";
@ -463,11 +497,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_followers(string $id): array public function accounts_followers($id)
{ {
return $this->_get('/api/v1/accounts/' . $id . '/followers'); return $this->_get('/api/v1/accounts/' . $id . '/followers');
} }
@ -477,11 +511,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_following(string $id): array public function accounts_following($id)
{ {
return $this->_get('/api/v1/accounts/' . $id . '/following'); return $this->_get('/api/v1/accounts/' . $id . '/following');
} }
@ -491,11 +525,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_statuses(string $id): array public function accounts_statuses($id)
{ {
return $this->_get('/api/v1/accounts/' . $id . '/statuses'); return $this->_get('/api/v1/accounts/' . $id . '/statuses');
} }
@ -505,11 +539,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_own_statuses(string $id): array public function accounts_own_statuses($id)
{ {
$response = $this->_get('/api/v1/accounts/' . $id . '/statuses?exclude_replies=1'); $response = $this->_get('/api/v1/accounts/' . $id . '/statuses?exclude_replies=1');
$result = []; $result = [];
@ -529,11 +563,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_follow(string $id): array public function accounts_follow($id)
{ {
return $this->_post('/api/v1/accounts/' . $id . '/follow'); return $this->_post('/api/v1/accounts/' . $id . '/follow');
} }
@ -543,11 +577,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_unfollow(string $id): array public function accounts_unfollow($id)
{ {
return $this->_post('/api/v1/accounts/' . $id . '/unfollow'); return $this->_post('/api/v1/accounts/' . $id . '/unfollow');
} }
@ -557,11 +591,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_block(string $id): array public function accounts_block($id)
{ {
return $this->_post('/api/v1/accounts/' . $id . '/block'); return $this->_post('/api/v1/accounts/' . $id . '/block');
} }
@ -571,11 +605,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_unblock(string $id): array public function accounts_unblock($id)
{ {
return $this->_post('/api/v1/accounts/' . $id . '/unblock'); return $this->_post('/api/v1/accounts/' . $id . '/unblock');
} }
@ -585,11 +619,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_mute(string $id): array public function accounts_mute($id)
{ {
return $this->_post('/api/v1/accounts/' . $id . '/mute'); return $this->_post('/api/v1/accounts/' . $id . '/mute');
} }
@ -599,11 +633,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function accounts_unmute(string $id): array public function accounts_unmute($id)
{ {
return $this->_post('/api/v1/accounts/' . $id . '/unmute'); return $this->_post('/api/v1/accounts/' . $id . '/unmute');
} }
@ -624,7 +658,7 @@ class Mastodon_api
* bool $response['muting'] * bool $response['muting']
* bool $response['requested'] * bool $response['requested']
*/ */
public function accounts_relationships(array $parameters): array public function accounts_relationships($parameters)
{ {
return $this->_get('/api/v1/accounts/relationships', $parameters); return $this->_get('/api/v1/accounts/relationships', $parameters);
} }
@ -638,7 +672,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function accounts_search(array $parameters): array public function accounts_search($parameters)
{ {
return $this->_get('/api/v1/accounts/search', $parameters); return $this->_get('/api/v1/accounts/search', $parameters);
} }
@ -648,7 +682,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function blocks(): array public function blocks()
{ {
return $this->_get('/api/v1/blocks'); return $this->_get('/api/v1/blocks');
} }
@ -658,7 +692,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function favourites(): array public function favourites()
{ {
return $this->_get('/api/v1/favourites'); return $this->_get('/api/v1/favourites');
} }
@ -668,7 +702,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function follow_requests(): array public function follow_requests()
{ {
return $this->_get('/api/v1/follow_requests'); return $this->_get('/api/v1/follow_requests');
} }
@ -678,11 +712,11 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function follow_requests_authorize(string $id): array public function follow_requests_authorize($id)
{ {
return $this->_post('/api/v1/follow_requests/authorize', array('id' => $id)); return $this->_post('/api/v1/follow_requests/authorize', array('id' => $id));
} }
@ -692,10 +726,10 @@ class Mastodon_api
* *
* @see https://your-domain/web/accounts/:id * @see https://your-domain/web/accounts/:id
* *
* @param string $id * @param int $id
* @return array $response * @return array $response
*/ */
public function follow_requests_reject(string $id): array public function follow_requests_reject($id)
{ {
return $this->_post('/api/v1/follow_requests/reject', array('id' => $id)); return $this->_post('/api/v1/follow_requests/reject', array('id' => $id));
} }
@ -708,11 +742,27 @@ class Mastodon_api
* @param string $uri username@domain of the person you want to follow * @param string $uri username@domain of the person you want to follow
* @return array $response * @return array $response
*/ */
public function follows($uri): array public function follows($uri)
{ {
return $this->_post('/api/v1/follows', array('uri' => $uri)); return $this->_post('/api/v1/follows', array('uri' => $uri));
} }
/**
* instance
*
* Getting instance information
*
* @return array $response
* string $response['uri']
* string $response['title']
* string $response['description']
* string $response['email']
*/
public function instance()
{
return $this->_get('/api/v1/instance');
}
/** /**
* mutes * mutes
* *
@ -720,7 +770,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function mutes(): array public function mutes()
{ {
return $this->_get('/api/v1/mutes'); return $this->_get('/api/v1/mutes');
} }
@ -733,7 +783,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function notifications($parameters): array public function notifications($parameters)
{ {
$url = '/api/v1/notifications'; $url = '/api/v1/notifications';
@ -747,7 +797,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function notifications_clear(): array public function notifications_clear()
{ {
return $this->_post('/api/v1/notifications/clear'); return $this->_post('/api/v1/notifications/clear');
} }
@ -759,7 +809,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function get_reports(): array public function get_reports()
{ {
return $this->_get('/api/v1/reports'); return $this->_get('/api/v1/reports');
} }
@ -776,7 +826,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function post_reports(array $parameters): array public function post_reports($parameters)
{ {
return $this->_post('/api/v1/reports', $parameters); return $this->_post('/api/v1/reports', $parameters);
} }
@ -792,7 +842,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function search(array $parameters): array public function search($parameters)
{ {
return $this->_get('/api/v1/search', $parameters); return $this->_get('/api/v1/search', $parameters);
} }
@ -802,11 +852,11 @@ class Mastodon_api
* *
* Fetching a status * Fetching a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses(string $id): array public function statuses($id)
{ {
return $this->_get('/api/v1/statuses/' . $id); return $this->_get('/api/v1/statuses/' . $id);
} }
@ -816,11 +866,11 @@ class Mastodon_api
* *
* Getting status context * Getting status context
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_context(string $id): array public function statuses_context($id)
{ {
return $this->_get('/api/v1/statuses/' . $id . '/context'); return $this->_get('/api/v1/statuses/' . $id . '/context');
} }
@ -830,11 +880,11 @@ class Mastodon_api
* *
* Getting a card associated with a status * Getting a card associated with a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_card(string $id): array public function statuses_card($id)
{ {
return $this->_get('/api/v1/statuses/' . $id . '/card'); return $this->_get('/api/v1/statuses/' . $id . '/card');
} }
@ -844,11 +894,11 @@ class Mastodon_api
* *
* Getting who reblogged a status * Getting who reblogged a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_reblogged_by(string $id): array public function statuses_reblogged_by($id)
{ {
return $this->_get('/api/v1/statuses/' . $id . '/reblogged_by'); return $this->_get('/api/v1/statuses/' . $id . '/reblogged_by');
} }
@ -858,11 +908,11 @@ class Mastodon_api
* *
* Getting who favourited a status * Getting who favourited a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_favourited_by(string $id): array public function statuses_favourited_by($id)
{ {
return $this->_get('/api/v1/statuses/' . $id . '/favourited_by'); return $this->_get('/api/v1/statuses/' . $id . '/favourited_by');
} }
@ -877,7 +927,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function post_media(array $parameters): array public function post_media($parameters)
{ {
return $this->_post('/api/v1/media', $parameters); return $this->_post('/api/v1/media', $parameters);
} }
@ -893,7 +943,7 @@ class Mastodon_api
* @param $parameters * @param $parameters
* @return array $response * @return array $response
*/ */
public function update_media(string $id, array $parameters): array public function update_media($id, $parameters)
{ {
return $this->_put('/api/v1/media/' . $id, $parameters); return $this->_put('/api/v1/media/' . $id, $parameters);
} }
@ -908,7 +958,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
private function _put(string $url, array $parameters = array()): array private function _put($url, $parameters = array())
{ {
$params["method"] = "PUT"; $params["method"] = "PUT";
@ -936,7 +986,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function post_statuses(array $parameters): array public function post_statuses($parameters)
{ {
return $this->_post('/api/v1/statuses', $parameters); return $this->_post('/api/v1/statuses', $parameters);
} }
@ -946,11 +996,11 @@ class Mastodon_api
* *
* Deleting a status * Deleting a status
* *
* @param string $id * @param int $id
* *
* @return array $response empty * @return array $response empty
*/ */
public function delete_statuses(string $id): array public function delete_statuses($id)
{ {
return $this->_delete('/api/v1/statuses/' . $id); return $this->_delete('/api/v1/statuses/' . $id);
} }
@ -964,7 +1014,7 @@ class Mastodon_api
* *
*/ */
private function _delete(string $url): array private function _delete($url)
{ {
$parameters = array(); $parameters = array();
$parameters["method"] = "DELETE"; $parameters["method"] = "DELETE";
@ -984,11 +1034,11 @@ class Mastodon_api
* *
* Deleting a scheduled status * Deleting a scheduled status
* *
* @param string $id * @param int $id
* *
* @return array $response empty * @return array $response empty
*/ */
public function delete_scheduled(string $id): array public function delete_scheduled($id)
{ {
return $this->_delete('/api/v1/scheduled_statuses/' . $id); return $this->_delete('/api/v1/scheduled_statuses/' . $id);
} }
@ -998,11 +1048,11 @@ class Mastodon_api
* *
* Reblogging a status * Reblogging a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_reblog(string $id): array public function statuses_reblog($id)
{ {
return $this->_post('/api/v1/statuses/' . $id . '/reblog'); return $this->_post('/api/v1/statuses/' . $id . '/reblog');
} }
@ -1012,11 +1062,11 @@ class Mastodon_api
* *
* Unreblogging a status * Unreblogging a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_unreblog(string $id): array public function statuses_unreblog($id)
{ {
return $this->_post('/api/v1/statuses/' . $id . '/unreblog'); return $this->_post('/api/v1/statuses/' . $id . '/unreblog');
} }
@ -1026,11 +1076,11 @@ class Mastodon_api
* *
* Favouriting a status * Favouriting a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_favourite(string $id): array public function statuses_favourite($id)
{ {
return $this->_post('/api/v1/statuses/' . $id . '/favourite'); return $this->_post('/api/v1/statuses/' . $id . '/favourite');
} }
@ -1040,28 +1090,16 @@ class Mastodon_api
* *
* Unfavouriting a status * Unfavouriting a status
* *
* @param string $id * @param int $id
* *
* @return array $response * @return array $response
*/ */
public function statuses_unfavourite(string $id): array public function statuses_unfavourite($id)
{ {
return $this->_post('/api/v1/statuses/' . $id . '/unfavourite'); return $this->_post('/api/v1/statuses/' . $id . '/unfavourite');
} }
/**
* scheduled_statuses
*
*
* @return array $response
*/
public function get_instance(): array
{
return $this->_get('/api/v1/instance');
}
/** /**
* scheduled_statuses * scheduled_statuses
* *
@ -1069,7 +1107,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function get_scheduled($parameters = array()): array public function get_scheduled($parameters = array())
{ {
return $this->_get('/api/v1/scheduled_statuses/', $parameters); return $this->_get('/api/v1/scheduled_statuses/', $parameters);
} }
@ -1079,7 +1117,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function timelines_home(): array public function timelines_home()
{ {
return $this->_get('/api/v1/timelines/home'); return $this->_get('/api/v1/timelines/home');
} }
@ -1092,7 +1130,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function timelines_public(array $parameters = array()): array public function timelines_public($parameters = array())
{ {
return $this->_get('/api/v1/timelines/public', $parameters); return $this->_get('/api/v1/timelines/public', $parameters);
} }
@ -1106,7 +1144,7 @@ class Mastodon_api
* *
* @return array $response * @return array $response
*/ */
public function timelines_tag(string $hashtag, array $parameters = array()): array public function timelines_tag($hashtag, $parameters = array())
{ {
return $this->_get('/api/v1/timelines/tag/' . $hashtag, $parameters); return $this->_get('/api/v1/timelines/tag/' . $hashtag, $parameters);
} }
@ -1122,12 +1160,13 @@ class Mastodon_api
* @param $host * @param $host
* @return string|null * @return string|null
*/ */
public function getInstanceNodeInfo(string $host): ?string public function getInstanceNodeInfo($host)
{ {
$curl = new Curl(); $curl = new Curl();
$url = "https://" . $host . "/.well-known/nodeinfo"; $url = "https://" . $host . "/.well-known/nodeinfo";
$reply = $curl->get($url); $reply = $curl->get($url);
$responseArray = json_decode($reply->response, true); $responseArray = json_decode($reply->response, true);
if (empty($responseArray)) { if (empty($responseArray)) {
$curl = new Curl(); $curl = new Curl();
@ -1154,7 +1193,7 @@ class Mastodon_api
* @param $accountParams array * @param $accountParams array
* @return MastodonAccount * @return MastodonAccount
*/ */
public function updateAccount(MastodonAccount $MastodonAccount, array $accountParams): MastodonAccount public function updateAccount(MastodonAccount $MastodonAccount, $accountParams)
{ {
$MastodonAccount->setUsername($accountParams['username']); $MastodonAccount->setUsername($accountParams['username']);
@ -1203,21 +1242,21 @@ class Mastodon_api
return $MastodonAccount; return $MastodonAccount;
} }
public function stringToDate(?string $string_date): DateTime public function stringToDate($string_date)
{ {
try { try {
return new DateTime($string_date); return new DateTime($string_date);
} catch (Exception $e) { } catch (Exception $e) {
} }
return new DateTime(); return "";
} }
/** /**
* getNotifications Hydrate an array of Notification from API reply * getNotifications Hydrate an array of Notification from API reply
* @param $notificationParams array * @param $notificationParams
* @return array * @return array
*/ */
public function getNotifications(array $notificationParams): array public function getNotifications($notificationParams)
{ {
$notifications = []; $notifications = [];
foreach ($notificationParams as $notificationParam) foreach ($notificationParams as $notificationParam)
@ -1230,7 +1269,7 @@ class Mastodon_api
* @param $notificationParams * @param $notificationParams
* @return Notification * @return Notification
*/ */
public function getSingleNotification($notificationParams): Notification public function getSingleNotification($notificationParams)
{ {
$notification = new Notification(); $notification = new Notification();
$notification->setId($notificationParams['id']); $notification->setId($notificationParams['id']);
@ -1242,62 +1281,12 @@ class Mastodon_api
return $notification; return $notification;
} }
/**
* get instance configuration from API reply
* @param $instantParams array
* @return Instance
*/
public function getInstanceConfiguration(array $instantParams): Instance
{
$Instance = new Instance();
$Configuration = new Configuration();
$Statuses = new Statuses();
$MediaAttachments = new MediaAttachments();
$Polls = new Polls();
if(isset($instantParams['configuration'])) {
//Dealing with statuses configuration
if(isset($instantParams['configuration']['statuses'])) {
$Statuses->setMaxCharacters($instantParams['configuration']['statuses']['max_characters']);
$Statuses->setMaxMediaAttachments($instantParams['configuration']['statuses']['max_media_attachments']);
$Statuses->setCharactersReservedPerUrl($instantParams['configuration']['statuses']['characters_reserved_per_url']);
}
if(isset($instantParams['configuration']['media_attachments'])) {
$MediaAttachments->setSupportedMimeTypes($instantParams['configuration']['media_attachments']['supported_mime_types']);
$MediaAttachments->setImageSizeLimit($instantParams['configuration']['media_attachments']['image_size_limit']);
$MediaAttachments->setImageMatrixLimit($instantParams['configuration']['media_attachments']['image_matrix_limit']);
$MediaAttachments->setVideoSizeLimit($instantParams['configuration']['media_attachments']['video_size_limit']);
$MediaAttachments->setVideoFrameRateLimit($instantParams['configuration']['media_attachments']['video_frame_rate_limit']);
$MediaAttachments->setVideoMatrixLimit($instantParams['configuration']['media_attachments']['video_matrix_limit']);
}
if(isset($instantParams['configuration']['polls'])) {
$Polls->setMaxOptions($instantParams['configuration']['polls']['max_options']);
$Polls->setMaxCharactersPerOption($instantParams['configuration']['polls']['max_characters_per_option']);
$Polls->setMinExpiration($instantParams['configuration']['polls']['min_expiration']);
$Polls->setMaxExpiration($instantParams['configuration']['polls']['max_expiration']);
}
} else if (isset($instantParams['pleroma'])) {
if (isset($instantParams['poll_limits'])) {
$Polls->setMaxOptions($instantParams['poll_limits']['max_options']);
$Polls->setMaxCharactersPerOption($instantParams['poll_limits']['max_option_chars']);
$Polls->setMinExpiration($instantParams['poll_limits']['min_expiration']);
$Polls->setMaxExpiration($instantParams['poll_limits']['max_expiration']);
}
if(isset($instantParams['max_toot_chars'])) {
$Statuses->setMaxCharacters($instantParams['max_toot_chars']);
}
}
$Configuration->setStatuses($Statuses);
$Configuration->setMediaAttachments($MediaAttachments);
$Configuration->setPolls($Polls);
$Instance->setConfiguration($Configuration);
return $Instance;
}
/** /**
* getSingleAccount Hydrate a MastodonAccount from API reply * getSingleAccount Hydrate a MastodonAccount from API reply
* @param $accountParams array * @param $accountParams
* @return MastodonAccount * @return MastodonAccount
*/ */
public function getSingleAccount(array $accountParams): MastodonAccount public function getSingleAccount($accountParams)
{ {
$MastodonAccount = new MastodonAccount(); $MastodonAccount = new MastodonAccount();
@ -1354,10 +1343,10 @@ class Mastodon_api
/** /**
* getSingleStatus Hydrate a Status from API reply * getSingleStatus Hydrate a Status from API reply
* @param $statusParams array * @param $statusParams
* @return Status * @return Status
*/ */
public function getSingleStatus(array $statusParams): Status public function getSingleStatus($statusParams)
{ {
$status = new Status(); $status = new Status();
@ -1488,7 +1477,7 @@ class Mastodon_api
* @param $statusParams * @param $statusParams
* @return array * @return array
*/ */
public function getStatuses($statusParams): array public function getStatuses($statusParams)
{ {
$statuses = []; $statuses = [];
foreach ($statusParams as $statusParam) foreach ($statusParams as $statusParam)
@ -1498,11 +1487,11 @@ class Mastodon_api
/** /**
* getScheduledStatuses Hydrate an array of Scheduled Status from API reply * getScheduledStatuses Hydrate an array of Scheduled Status from API reply
* @param $statusParams array * @param $statusParams
* @param $account MastodonAccount * @param $account
* @return array * @return array
*/ */
public function getScheduledStatuses(array $statusParams, MastodonAccount $account): array public function getScheduledStatuses($statusParams, $account)
{ {
$statuses = []; $statuses = [];
foreach ($statusParams as $statusParam) foreach ($statusParams as $statusParam)
@ -1513,11 +1502,11 @@ class Mastodon_api
/** /**
* getSingleScheduledStatus Hydrate a scheduled Status from API reply * getSingleScheduledStatus Hydrate a scheduled Status from API reply
* @param $statusParams array * @param $statusParams
* @param $account MastodonAccount * @param $account
* @return Status * @return Status
*/ */
public function getSingleScheduledStatus(array $statusParams, MastodonAccount $account): Status public function getSingleScheduledStatus($statusParams, $account)
{ {
$status = new Status(); $status = new Status();
@ -1556,8 +1545,6 @@ class Mastodon_api
$attachment->setMeta(serialize($_m['meta'])); $attachment->setMeta(serialize($_m['meta']));
if ($_m['description']) if ($_m['description'])
$attachment->setDescription($_m['description']); $attachment->setDescription($_m['description']);
else
$attachment->setDescription("");
$media_attachments[] = $attachment; $media_attachments[] = $attachment;
} }
$status->setMediaAttachments($media_attachments); $status->setMediaAttachments($media_attachments);
@ -1591,10 +1578,10 @@ class Mastodon_api
/** /**
* getSingleAttachment Hydrate an Attachment from API reply * getSingleAttachment Hydrate an Attachment from API reply
* @param $mediaParams array * @param $mediaParams
* @return Attachment * @return Attachment
*/ */
public function getSingleAttachment(array $mediaParams): Attachment public function getSingleAttachment($mediaParams)
{ {
$attachment = new Attachment(); $attachment = new Attachment();

View file

@ -6,8 +6,10 @@ namespace App\SocialEntity;
class Application class Application
{ {
private string $name; /** @var string */
private string $website; private $name;
/** @var string */
private $website;
/** /**
* @return string * @return string

View file

@ -5,15 +5,22 @@ namespace App\SocialEntity;
class Attachment class Attachment
{ {
/** @var string */
private string $id; private $id;
private string $type; /** @var string */
private string $url; private $type;
private string $remote_url; /** @var string */
private string $preview_url; private $url;
private string $text_url; /** @var string */
private string $meta; private $remote_url;
private string $description; /** @var string */
private $preview_url;
/** @var string */
private $text_url;
/** @var string */
private $meta;
/** @var string */
private $description;
/** /**
* @return string * @return string

View file

@ -5,18 +5,30 @@ namespace App\SocialEntity;
class Card class Card
{ {
private string $url; /** @var string */
private string $title; private $url;
private string $description; /** @var string */
private string $image; private $title;
private string $type; /** @var string */
private string $author_name; private $description;
private string $author_url; /** @var string */
private string $provider_name; private $image;
private string $provider_url; /** @var string */
private string $html; private $type;
private int $width; /** @var string */
private int $height; private $author_name;
/** @var string */
private $author_url;
/** @var string */
private $provider_name;
/** @var string */
private $provider_url;
/** @var string */
private $html;
/** @var int */
private $width;
/** @var int */
private $height;
/** /**
* @return string * @return string
@ -210,4 +222,5 @@ class Card
$this->height = $height; $this->height = $height;
} }
} }

View file

@ -3,17 +3,20 @@
namespace App\SocialEntity; namespace App\SocialEntity;
use App\Security\MastodonAccount;
class Client class Client
{ {
private string $id; private $id;
private string $host;
private string $client_id; private $host;
private string $client_secret;
private MastodonAccount $account; private $client_id;
private string $code;
private $client_secret;
private $account;
private $code;
public function getId(): ?int public function getId(): ?int
{ {

View file

@ -3,52 +3,55 @@
namespace App\SocialEntity; namespace App\SocialEntity;
use DateTime; use DateTime;
use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
class Compose class Compose
{ {
private string $id; private $id;
private ?string $content_warning = null;
private ?string $content = null;
private string $visibility; private $content_warning;
private DateTime $created_at;
private DateTime $scheduled_at;
private DateTime $sent_at;
private bool $sensitive;
private ?string $in_reply_to_id = null;
private string $timeZone; private $content;
/** @var PollOption[] */
private ?array $poll_options = null;
private ?int $poll_expires_at = null;
private ?bool $poll_multiple = null;
public function getAttachPoll(): ?bool private $visibility;
{
return $this->attach_poll;
}
public function setAttachPoll(?bool $attach_poll): void private $created_at;
{
$this->attach_poll = $attach_poll; private $scheduled_at;
}
private ?bool $attach_poll = null; private $sent_at;
private $sensitive;
private $in_reply_to_id;
private $timeZone;
private $poll_options;
/** @var int */
private $poll_expires_at;
/** @var bool */
private $poll_multiple;
public function __construct() public function __construct()
{ {
$this->poll_options = array(); $this->poll_options = new ArrayCollection();
} }
/**
public function getTimeZone(): string * @return mixed
*/
public function getTimeZone()
{ {
return $this->timeZone; return $this->timeZone;
} }
/**
* @param mixed $timeZone
*/
public function setTimeZone($timeZone): void public function setTimeZone($timeZone): void
{ {
$this->timeZone = $timeZone; $this->timeZone = $timeZone;
@ -60,7 +63,7 @@ class Compose
public function getSent() public function getSent()
{ {
return ($this->sent_at != null && !empty($this->sent_at)); return ($this->sent_at != null);
} }
public function getId(): ?int public function getId(): ?int
@ -105,23 +108,29 @@ class Compose
} }
public function getSensitive(): bool /**
* @return boolean
*/
public function getSensitive()
{ {
return $this->sensitive; return $this->sensitive;
} }
/**
* @param mixed $sensitive
*/
public function setSensitive(bool $sensitive): void public function setSensitive(bool $sensitive): void
{ {
$this->sensitive = $sensitive; $this->sensitive = $sensitive;
} }
public function getCreatedAt(): ?DateTime public function getCreatedAt(): ?DateTimeInterface
{ {
return $this->created_at; return $this->created_at;
} }
public function setCreatedAt(DateTime $created_at): self public function setCreatedAt(DateTimeInterface $created_at): self
{ {
$this->created_at = $created_at; $this->created_at = $created_at;
@ -152,29 +161,41 @@ class Compose
return $this; return $this;
} }
/**
* @return ArrayCollection|null
public function getPollOptions(): ?array */
public function getPollOptions(): ?ArrayCollection
{ {
return $this->poll_options; return $this->poll_options;
} }
/**
public function setPollOptions(?array $poll_options): void * @param ArrayCollection $poll_options
*/
public function setPollOptions(?ArrayCollection $poll_options): void
{ {
$this->poll_options = $poll_options; $this->poll_options = $poll_options;
} }
/**
* @return int
*/
public function getPollExpiresAt(): ?int public function getPollExpiresAt(): ?int
{ {
return $this->poll_expires_at; return $this->poll_expires_at;
} }
/**
* @param int $poll_expires_at
*/
public function setPollExpiresAt(?int $poll_expires_at): void public function setPollExpiresAt(?int $poll_expires_at): void
{ {
$this->poll_expires_at = $poll_expires_at; $this->poll_expires_at = $poll_expires_at;
} }
/**
* @return bool
*/
public function isPollMultiple(): ?bool public function isPollMultiple(): ?bool
{ {
return $this->poll_multiple; return $this->poll_multiple;

View file

@ -3,21 +3,20 @@
namespace App\SocialEntity; namespace App\SocialEntity;
use App\Security\MastodonAccount; use DateTimeInterface;
use DateTime;
class CustomField class CustomField
{ {
private string $id; private $id;
private string $name; private $name;
private string $value; private $value;
private \DateTime $verified_at; private $verified_at;
private MastodonAccount $mastodonAccount; private $mastodonAccount;
public function __construct() public function __construct()
@ -41,12 +40,12 @@ class CustomField
return $this; return $this;
} }
public function getVerifiedAt(): ?DateTime public function getVerifiedAt(): ?DateTimeInterface
{ {
return $this->verified_at; return $this->verified_at;
} }
public function setVerifiedAt(?DateTime $verified_at): self public function setVerifiedAt(?DateTimeInterface $verified_at): self
{ {
$this->verified_at = $verified_at; $this->verified_at = $verified_at;

View file

@ -3,21 +3,19 @@
namespace App\SocialEntity; namespace App\SocialEntity;
use App\Security\MastodonAccount;
class Emoji class Emoji
{ {
private string $id; private $id;
private string $shortcode; private $shortcode;
private string $static_url; private $static_url;
private string $url; private $url;
private bool $visible_in_picker; private $visible_in_picker;
private MastodonAccount $mastodonAccount; private $mastodonAccount;
public function __construct() public function __construct()

View file

@ -1,225 +0,0 @@
<?php
namespace App\SocialEntity;
class Statuses {
private int $max_characters = 500;
private int $max_media_attachments = 4;
private int $characters_reserved_per_url = 23;
public function getMaxCharacters(): int
{
return $this->max_characters;
}
public function setMaxCharacters(int $max_characters): void
{
$this->max_characters = $max_characters;
}
public function getMaxMediaAttachments(): int
{
return $this->max_media_attachments;
}
public function setMaxMediaAttachments(int $max_media_attachments): void
{
$this->max_media_attachments = $max_media_attachments;
}
public function getCharactersReservedPerUrl(): int
{
return $this->characters_reserved_per_url;
}
public function setCharactersReservedPerUrl(int $characters_reserved_per_url): void
{
$this->characters_reserved_per_url = $characters_reserved_per_url;
}
}
class MediaAttachments {
private array $supported_mime_types = ["image/jpeg","image/png","image/gif","image/heic","image/heif","image/webp","image/avif","video/webm","video/mp4","video/quicktime","video/ogg","audio/wave","audio/wav","audio/x-wav","audio/x-pn-wave","audio/vnd.wave","audio/ogg","audio/vorbis","audio/mpeg","audio/mp3","audio/webm","audio/flac","audio/aac","audio/m4a","audio/x-m4a","audio/mp4","audio/3gpp","video/x-ms-asf"];
private int $image_size_limit = 16777216;
private int $image_matrix_limit = 33177600;
private int $video_size_limit = 103809024;
private int $video_frame_rate_limit = 120;
private int $video_matrix_limit = 8294400;
public function getSupportedMimeTypes(): array
{
return $this->supported_mime_types;
}
public function setSupportedMimeTypes(array $supported_mime_types): void
{
$this->supported_mime_types = $supported_mime_types;
}
public function getSupportedFiles() : string {
$values = "/(\.|\/)(gif|jpe?g|apng|png|mp4|mp3|avi|mov|webm|wmv|flv|wav|ogg)$/i";
if(isset($this->supported_mime_types) && count($this->supported_mime_types) >0) {
$values = "/(\.|\/)(";
foreach ($this->supported_mime_types as $value) {
$cleanedValue = preg_replace("#(image/)|(video/)|(audio/)#","",$value,);
if(!str_contains($cleanedValue, '.') && !str_contains($cleanedValue, '-')) {
$values .= $cleanedValue.'|';
}
}
$values .= "jpg)$/i";
}
return $values;
}
public function getImageSizeLimit(): int
{
return $this->image_size_limit;
}
public function setImageSizeLimit(int $image_size_limit): void
{
$this->image_size_limit = $image_size_limit;
}
public function getImageMatrixLimit(): int
{
return $this->image_matrix_limit;
}
public function setImageMatrixLimit(int $image_matrix_limit): void
{
$this->image_matrix_limit = $image_matrix_limit;
}
public function getVideoSizeLimit(): int
{
return $this->video_size_limit;
}
public function setVideoSizeLimit(int $video_size_limit): void
{
$this->video_size_limit = $video_size_limit;
}
public function getVideoFrameRateLimit(): int
{
return $this->video_frame_rate_limit;
}
public function setVideoFrameRateLimit(int $video_frame_rate_limit): void
{
$this->video_frame_rate_limit = $video_frame_rate_limit;
}
public function getVideoMatrixLimit(): int
{
return $this->video_matrix_limit;
}
public function setVideoMatrixLimit(int $video_matrix_limit): void
{
$this->video_matrix_limit = $video_matrix_limit;
}
}
class Polls {
private int $max_options = 4;
private int $max_characters_per_option = 50;
private int $min_expiration = 300;
private int $max_expiration = 2629746;
public function getMaxOptions(): int
{
return $this->max_options;
}
public function setMaxOptions(int $max_options): void
{
$this->max_options = $max_options;
}
public function getMaxCharactersPerOption(): int
{
return $this->max_characters_per_option;
}
public function setMaxCharactersPerOption(int $max_characters_per_option): void
{
$this->max_characters_per_option = $max_characters_per_option;
}
public function getMinExpiration(): int
{
return $this->min_expiration;
}
public function setMinExpiration(int $min_expiration): void
{
$this->min_expiration = $min_expiration;
}
public function getMaxExpiration(): int
{
return $this->max_expiration;
}
public function setMaxExpiration(int $max_expiration): void
{
$this->max_expiration = $max_expiration;
}
}
class Configuration {
private Statuses $statuses;
private MediaAttachments $mediaAttachments;
public function getStatuses(): Statuses
{
return $this->statuses;
}
public function setStatuses(Statuses $statuses): void
{
$this->statuses = $statuses;
}
public function getMediaAttachments(): MediaAttachments
{
return $this->mediaAttachments;
}
public function setMediaAttachments(MediaAttachments $mediaAttachments): void
{
$this->mediaAttachments = $mediaAttachments;
}
public function getPolls(): Polls
{
return $this->polls;
}
public function setPolls(Polls $polls): void
{
$this->polls = $polls;
}
private Polls $polls;
}
class Instance
{
private Configuration $configuration;
public function getConfiguration(): Configuration
{
return $this->configuration;
}
public function setConfiguration(Configuration $configuration): void
{
$this->configuration = $configuration;
}
}

View file

@ -1,68 +1,70 @@
<?php <?php
namespace App\Security; namespace App\SocialEntity;
use App\SocialEntity\Client;
use App\SocialEntity\CustomField;
use App\SocialEntity\Emoji;
use Symfony\Component\Security\Core\User\UserInterface;
class MastodonAccount implements UserInterface use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
class MastodonAccount
{ {
private string $acct;
private string $id;
private string $account_id; private $id;
private string $username; private $account_id;
private string $display_name; private $username;
private bool $locked; private $acct;
private \DateTime $created_at; private $display_name;
private int $followers_count; private $locked;
private int $following_count; private $created_at;
private int $statuses_count; private $followers_count;
private string $note; private $following_count;
private string $url; private $statuses_count;
private string $avatar; private $note;
private string $avatar_static; private $url;
private string $header; private $avatar;
private string $header_static; private $avatar_static;
private MastodonAccount $moved; private $header;
private bool $bot; private $header_static;
private string $instance; private $moved;
private Client $client; private $bot;
private string $token; private $instance;
private array $Fields; private $client;
/** @var Emoji[] */
private array $Emojis;
private string $default_sensitivity; private $token;
private string $default_visibility; private $Fields;
private $Emojis;
private $default_sensitivity;
private $default_visibility;
public function __construct() public function __construct()
{ {
$this->Fields = array(); $this->Fields = new ArrayCollection();
$this->Emojis = array(); $this->Emojis = new ArrayCollection();
} }
@ -119,12 +121,12 @@ class MastodonAccount implements UserInterface
return $this; return $this;
} }
public function getCreatedAt(): ?\DateTime public function getCreatedAt(): ?DateTimeInterface
{ {
return $this->created_at; return $this->created_at;
} }
public function setCreatedAt(\DateTime $created_at): self public function setCreatedAt(DateTimeInterface $created_at): self
{ {
$this->created_at = $created_at; $this->created_at = $created_at;
@ -322,52 +324,59 @@ class MastodonAccount implements UserInterface
return $this; return $this;
} }
/**
public function getFields(): array * @return Collection|CustomField[]
*/
public function getFields(): Collection
{ {
return $this->Fields; return $this->Fields;
} }
public function addField(CustomField $field): self public function addField(CustomField $field): self
{ {
if (in_array($field, $this->Fields) === false) { if (!$this->Fields->contains($field)) {
$this->Fields[] = $field; $this->Fields[] = $field;
$field->setMastodonAccount($this); $field->setMastodonAccount($this);
} }
return $this; return $this;
} }
public function removeField(CustomField $field): self public function removeField(CustomField $field): self
{ {
if ($this->Fields->contains($field)) {
if (($key = array_search($field, $this->Fields)) !== false) { $this->Fields->removeElement($field);
unset($this->Fields[$key]);
// set the owning side to null (unless already changed) // set the owning side to null (unless already changed)
if ($field->getMastodonAccount() === $this) { if ($field->getMastodonAccount() === $this) {
$field->setMastodonAccount(null); $field->setMastodonAccount(null);
} }
} }
return $this; return $this;
} }
public function getEmojis(): array /**
* @return Collection|Emoji[]
*/
public function getEmojis(): Collection
{ {
return $this->Emojis; return $this->Emojis;
} }
public function addEmoji(Emoji $emoji): self public function addEmoji(Emoji $emoji): self
{ {
if (in_array($emoji, $this->Emojis) === false) { if (!$this->Emojis->contains($emoji)) {
$this->Emojis[] = $emoji; $this->Emojis[] = $emoji;
$emoji->setMastodonAccount($this); $emoji->setMastodonAccount($this);
} }
return $this; return $this;
} }
public function removeEmoji(Emoji $emoji): self public function removeEmoji(Emoji $emoji): self
{ {
if (($key = array_search($emoji, $this->Emojis)) !== false) { if ($this->Emojis->contains($emoji)) {
unset($this->Emojis[$key]); $this->Emojis->removeElement($emoji);
// set the owning side to null (unless already changed) // set the owning side to null (unless already changed)
if ($emoji->getMastodonAccount() === $this) { if ($emoji->getMastodonAccount() === $this) {
$emoji->setMastodonAccount(null); $emoji->setMastodonAccount(null);
@ -381,7 +390,7 @@ class MastodonAccount implements UserInterface
/** /**
* @return mixed * @return mixed
*/ */
public function getDefaultSensitivity(): mixed public function getDefaultSensitivity()
{ {
return $this->default_sensitivity; return $this->default_sensitivity;
} }
@ -409,52 +418,6 @@ class MastodonAccount implements UserInterface
{ {
$this->default_visibility = $default_visibility; $this->default_visibility = $default_visibility;
} }
/**
* @var list<string> The user roles
*/
private $roles = [];
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->acct;
}
/**
* @see UserInterface
*
* @return list<string>
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
/**
* @param list<string> $roles
*/
public function setRoles(array $roles): static
{
$this->roles = $roles;
return $this;
}
/**
* @see UserInterface
*/
public function eraseCredentials(): void
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
} }

View file

@ -4,10 +4,14 @@ namespace App\SocialEntity;
class Mention class Mention
{ {
private string $url; /** @var string */
private string $username; private $url;
private string $acct; /** @var string */
private string $id; private $username;
/** @var string */
private $acct;
/** @var string */
private $id;
/** /**

View file

@ -3,16 +3,20 @@
namespace App\SocialEntity; namespace App\SocialEntity;
use App\Security\MastodonAccount;
use DateTime; use DateTime;
class Notification class Notification
{ {
private string $id; /** @var string */
private string $type; private $id;
private DateTime $created_at; /** @var string */
private MastodonAccount $account; private $type;
private Status $status; /** @var DateTime */
private $created_at;
/** @var MastodonAccount */
private $account;
/** @var Status */
private $status;
/** /**

View file

@ -8,19 +8,26 @@ use DateTime;
class Poll class Poll
{ {
private string $id; /** @var string */
private DateTime $expires_at; private $id;
private bool $expired; /** @var DateTime */
private bool $multiple; private $expires_at;
private int $votes_count; /** @var bool */
private int $voters_count; private $expired;
private bool $voted; /** @var bool */
private $multiple;
/** @var int */
private $votes_count;
/** @var int */
private $voters_count;
/** @var bool */
private $voted;
/** @var int[] */ /** @var int[] */
private array $own_votes; private $own_votes;
/** @var PollOption[] */ /** @var PollOption[] */
private array $options; private $options;
/** @var Emoji[] */ /** @var Emoji[] */
private array $emojis; private $emojis;
/** /**
* @return string * @return string

View file

@ -6,27 +6,38 @@ namespace App\SocialEntity;
class PollOption class PollOption
{ {
private ?string $title = null; /** @var string */
private ?int $votes_count = null; private $title;
/** @var int */
private $votes_count;
/**
* @return string
*/
public function getTitle(): ?string public function getTitle(): ?string
{ {
return $this->title; return $this->title;
} }
/**
* @param string $title
*/
public function setTitle(?string $title): void public function setTitle(?string $title): void
{ {
$this->title = $title; $this->title = $title;
} }
/**
* @return int
*/
public function getVotesCount(): ?int public function getVotesCount(): ?int
{ {
return $this->votes_count; return $this->votes_count;
} }
/**
* @param int $votes_count
*/
public function setVotesCount(?int $votes_count): void public function setVotesCount(?int $votes_count): void
{ {
$this->votes_count = $votes_count; $this->votes_count = $votes_count;

View file

@ -3,43 +3,66 @@
namespace App\SocialEntity; namespace App\SocialEntity;
use App\Security\MastodonAccount;
use DateTime; use DateTime;
class Status class Status
{ {
private string $id; /** @var string */
private string $uri; private $id;
private string $url; /** @var string */
private MastodonAccount $account; private $uri;
private ?string $in_reply_to_id; /** @var string */
private ?string $in_reply_to_account_id; private $url;
private ?string $content; /** @var MastodonAccount */
private DateTime $created_at; private $account;
private DateTime $scheduled_at; /** @var string */
private $in_reply_to_id;
/** @var string */
private $in_reply_to_account_id;
/** @var string */
private $content;
/** @var DateTime */
private $created_at;
/** @var DateTime */
private $scheduled_at;
/** @var Emoji[] */ /** @var Emoji[] */
private array $emojis = []; private $emojis = [];
private int $replies_count; /** @var int */
private int $reblogs_count; private $replies_count;
private int $favourites_count; /** @var int */
private bool $reblogged; private $reblogs_count;
private bool $favourited; /** @var int */
private bool $muted; private $favourites_count;
private bool $sensitive_; /** @var boolean */
private ?string $spoiler_text; private $reblogged;
private string $visibility; /** @var boolean */
private $favourited;
/** @var boolean */
private $muted;
/** @var boolean */
private $sensitive_;
/** @var string */
private $spoiler_text;
/** @var string */
private $visibility;
/** @var Attachment[] */ /** @var Attachment[] */
private array $media_attachments = []; private $media_attachments = [];
/** @var Mention[] */ /** @var Mention[] */
private array $mentions = []; private $mentions = [];
/** @var Tag[] */ /** @var Tag[] */
private array $tags = []; private $tags = [];
private Card $card; /** @var Card */
private Application $application; private $card;
private string $language; /** @var Application */
private bool $pinned; private $application;
private Status $reblog; /** @var string */
private Poll $poll; private $language;
/** @var boolean */
private $pinned;
/** @var Status */
private $reblog;
/** @var Poll */
private $poll;
/** /**
* @return string * @return string
@ -106,15 +129,15 @@ class Status
} }
/** /**
* @return string|null * @return string
*/ */
public function getInReplyToId(): ?string public function getInReplyToId(): string
{ {
return $this->in_reply_to_id; return $this->in_reply_to_id;
} }
/** /**
* @param mixed $in_reply_to_id * @param string $in_reply_to_id
*/ */
public function setInReplyToId(?string $in_reply_to_id): void public function setInReplyToId(?string $in_reply_to_id): void
{ {
@ -130,7 +153,7 @@ class Status
} }
/** /**
* @param mixed $in_reply_to_account_id * @param string $in_reply_to_account_id
*/ */
public function setInReplyToAccountId(?string $in_reply_to_account_id): void public function setInReplyToAccountId(?string $in_reply_to_account_id): void
{ {
@ -138,17 +161,17 @@ class Status
} }
/** /**
* @return string|null * @return string
*/ */
public function getContent(): ?string public function getContent(): string
{ {
return $this->content; return $this->content;
} }
/** /**
* @param mixed $content * @param string $content
*/ */
public function setContent(?string $content): void public function setContent(string $content): void
{ {
$this->content = $content; $this->content = $content;
} }
@ -162,7 +185,7 @@ class Status
} }
/** /**
* @param mixed $created_at * @param DateTime $created_at
*/ */
public function setCreatedAt(?DateTime $created_at): void public function setCreatedAt(?DateTime $created_at): void
{ {
@ -323,7 +346,7 @@ class Status
} }
/** /**
* @param mixed $spoiler_text * @param string $spoiler_text
*/ */
public function setSpoilerText(?string $spoiler_text): void public function setSpoilerText(?string $spoiler_text): void
{ {

View file

@ -6,10 +6,14 @@ namespace App\SocialEntity;
class Tag class Tag
{ {
private string $name; /** @var string */
private string $url; private $name;
private array $history = []; /** @var string */
private Status $status; private $url;
/** @var array */
private $history = [];
/** @var Status */
private $status;
/** /**
* @return string * @return string

Some files were not shown because too many files have changed in this diff Show more