Merge branch 'feat-265-realtime' into feat-265-realtime-e2e
|
@ -15,12 +15,7 @@ then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
echo "Updating git repository $1 / $2"
|
||||
|
||||
git fetch origin
|
||||
git reset --hard origin/master
|
||||
|
||||
if test $(find "./app/db/DBIP/dbip-country-lite-2020-01.mmdb" -mmin +259200)
|
||||
if test $(find "./app/db/DBIP/dbip-country-lite-2021-02.mmdb" -mmin +259200)
|
||||
then
|
||||
printf "${RED}GEO country DB has not been updated for more than 6 months. Go to https://db-ip.com/db/download/ip-to-country-lite to download a newer version${NC}\n"
|
||||
fi
|
||||
|
|
33
CHANGES.md
|
@ -1,3 +1,36 @@
|
|||
# Version 0.8.0 (Not Released Yet)
|
||||
|
||||
- Anonymous login
|
||||
|
||||
# Version 0.7.1 (Not Released Yet)
|
||||
|
||||
## Features
|
||||
|
||||
- Better error logs on appwrite cretificates worker
|
||||
- Added option for Redis authentication
|
||||
- Force adding a security email on setup
|
||||
- SMTP is now disabled by default, no dummy SMTP is included in setup
|
||||
- Added a new endpoint that returns the server and SDKs latest versions numbers #941
|
||||
|
||||
## Upgrades
|
||||
|
||||
- Upgraded redis extenstion lib to version 5.3.3
|
||||
- Upgraded maxmind extenstion lib to version 1.10.0
|
||||
- Upgraded utopia-php/cli lib to version 0.10.0
|
||||
- Upgraded matomo/device-detector lib to version 4.1.0
|
||||
- Upgraded dragonmantank/cron-expression lib to version 3.1.0
|
||||
- Upgraded influxdb/influxdb-php lib to version 1.15.2
|
||||
- Upgraded phpmailer/phpmailer lib to version 6.3.0
|
||||
- Upgraded adhocore/jwt lib to version 1.1.2
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Updated missing storage env vars
|
||||
|
||||
## Security
|
||||
|
||||
- Fixed an XSS vulnerability in the Appwrite console
|
||||
|
||||
# Version 0.7.0
|
||||
|
||||
## Features
|
||||
|
|
|
@ -90,6 +90,35 @@ Appwrite uses an internal micro-framework called Litespeed.js to build simple UI
|
|||
|
||||
After finishing the installation process, you can start writing and editing code.
|
||||
|
||||
|
||||
#### Advanced Topics
|
||||
We love to create issues that are good for begginers and label them as `good for begginers` or `hacktoberfest`, but some more advanced topics might require extra knowledge. Below is a list of links you can use to learn more about some of the more advance topics that will help you master the Appwrite codebase.
|
||||
|
||||
##### Tools and Libs
|
||||
- [Docker](https://www.docker.com/get-started)
|
||||
- [PHP FIG](https://www.php-fig.org/) - [PSR-1](https://www.php-fig.org/psr/psr-1/) and [PSR-4](https://www.php-fig.org/psr/psr-4/)
|
||||
- [PHP Swoole](https://www.swoole.co.uk/)
|
||||
|
||||
Learn more at our [Technology Stack](## Technology Stack) section.
|
||||
|
||||
##### Network and Protocols
|
||||
- [OSI Model](https://en.wikipedia.org/wiki/OSI_model)
|
||||
- [TCP vs UDP](https://www.guru99.com/tcp-vs-udp-understanding-the-difference.html#:~:text=TCP%20is%20a%20connection%2Doriented,speed%20of%20UDP%20is%20faster&text=TCP%20does%20error%20checking%20and,but%20it%20discards%20erroneous%20packets.)
|
||||
- [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol)
|
||||
- [REST API](https://en.wikipedia.org/wiki/Representational_state_transfer)
|
||||
- [GraphQL](https://en.wikipedia.org/wiki/GraphQL)
|
||||
- [gRPC](https://en.wikipedia.org/wiki/GRPC)
|
||||
|
||||
##### Architecture
|
||||
- [Microservices vs Monolithic](https://www.mulesoft.com/resources/api/microservices-vs-monolithic#:~:text=Microservices%20architecture%20vs%20monolithic%20architecture&text=A%20monolithic%20application%20is%20built%20as%20a%20single%20unit.&text=To%20make%20any%20alterations%20to,formally%20with%20business%2Doriented%20APIs.)
|
||||
- [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) - Appwrite console architecture
|
||||
|
||||
##### Security
|
||||
- [Appwrite Auth and ACL](https://github.com/appwrite/appwrite/blob/0.7.x/docs/specs/authentication.drawio.svg)
|
||||
- [OAuth](https://en.wikipedia.org/wiki/OAuth)
|
||||
- [Encryption](https://medium.com/searchencrypt/what-is-encryption-how-does-it-work-e8f20e340537#:~:text=Encryption%20is%20a%20process%20that,%2C%20or%20decrypt%2C%20the%20information.)
|
||||
- [Hashing](https://searchsqlserver.techtarget.com/definition/hashing#:~:text=Hashing%20is%20the%20transformation%20of,it%20using%20the%20original%20value.)
|
||||
|
||||
## Architecture
|
||||
|
||||
Appwrite's current structure is a combination of both [Monolithic](https://en.wikipedia.org/wiki/Monolithic_application) and [Microservice](https://en.wikipedia.org/wiki/Microservices) architectures, but our final goal, as we grow, is to be using only microservices.
|
||||
|
@ -114,7 +143,6 @@ Appwrite's current structure is a combination of both [Monolithic](https://en.wi
|
|||
├── docs # Docs and tutorials
|
||||
│ ├── examples
|
||||
│ ├── references
|
||||
│ ├── sdks
|
||||
│ ├── services
|
||||
│ ├── specs
|
||||
│ └── tutorials
|
||||
|
@ -128,13 +156,14 @@ Appwrite's current structure is a combination of both [Monolithic](https://en.wi
|
|||
│ └── Appwrite
|
||||
│ ├── Auth
|
||||
│ ├── Database
|
||||
│ ├── Detector
|
||||
│ ├── Docker
|
||||
│ ├── Event
|
||||
│ ├── Extend
|
||||
│ ├── Migration
|
||||
│ ├── Network
|
||||
│ ├── OpenSSL
|
||||
│ ├── Resize
|
||||
│ ├── Storage
|
||||
│ ├── Specification
|
||||
│ ├── Task
|
||||
│ ├── Template
|
||||
│ ├── URL
|
||||
|
|
14
Dockerfile
|
@ -14,9 +14,9 @@ RUN composer update --ignore-platform-reqs --optimize-autoloader \
|
|||
|
||||
FROM php:7.4-cli-alpine as step1
|
||||
|
||||
ENV PHP_REDIS_VERSION=5.3.2 \
|
||||
ENV PHP_REDIS_VERSION=5.3.3 \
|
||||
PHP_SWOOLE_VERSION=v4.5.8 \
|
||||
PHP_MAXMINDDB_VERSION=v1.8.0 \
|
||||
PHP_MAXMINDDB_VERSION=v1.10.0 \
|
||||
PHP_XDEBUG_VERSION=sdebug_2_9-beta
|
||||
|
||||
RUN \
|
||||
|
@ -90,8 +90,11 @@ ENV _APP_SERVER=swoole \
|
|||
_APP_INFLUXDB_PORT=8086 \
|
||||
_APP_STATSD_HOST=telegraf \
|
||||
_APP_STATSD_PORT=8125 \
|
||||
_APP_SMTP_HOST=smtp \
|
||||
_APP_SMTP_PORT=25 \
|
||||
_APP_SMTP_HOST= \
|
||||
_APP_SMTP_PORT= \
|
||||
_APP_SMTP_SECURE= \
|
||||
_APP_SMTP_USERNAME= \
|
||||
_APP_SMTP_PASSWORD= \
|
||||
_APP_FUNCTIONS_TIMEOUT=900 \
|
||||
_APP_FUNCTIONS_CONTAINERS=10 \
|
||||
_APP_FUNCTIONS_CPUS=1 \
|
||||
|
@ -106,9 +109,6 @@ ENV _APP_SERVER=swoole \
|
|||
# 1 Day = 86400 s
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400 \
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
#ENV _APP_SMTP_SECURE ''
|
||||
#ENV _APP_SMTP_USERNAME ''
|
||||
#ENV _APP_SMTP_PASSWORD ''
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ docker run -it --rm ,
|
|||
Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-linux native hosts, the server might take a few minutes to start after installation completes.
|
||||
|
||||
|
||||
For advanced production and custom installation, check out our Docker [environment variables](docs/tutorials/environment-variables.md) docs. You can also use our public [docker-compose.yml](https://appwrite.io/docker-compose.yml) file to manually set up and environment.
|
||||
For advanced production and custom installation, check out our Docker [environment variables](docs/tutorials/environment-variables.md) docs. You can also use our public [docker-compose.yml](https://appwrite.io/docker-compose.yml) file to manually set up an environment.
|
||||
|
||||
### Upgrade from an Older Version
|
||||
|
||||
|
@ -94,6 +94,7 @@ Getting started with Appwrite is as easy as creating a new project, choosing you
|
|||
* [Getting Started for Web](https://appwrite.io/docs/getting-started-for-web)
|
||||
* [Getting Started for Flutter](https://appwrite.io/docs/getting-started-for-flutter)
|
||||
* [Getting Started for Server](https://appwrite.io/docs/getting-started-for-server)
|
||||
* [Getting Started for CLI](https://appwrite.io/docs/command-line)
|
||||
* Getting Started for Android (Coming soon...)
|
||||
* Getting Started for iOS (Coming soon...)
|
||||
|
||||
|
@ -132,13 +133,13 @@ Looking for more SDKs? - Help us by contributing a pull request to our [SDK Gene
|
|||
|
||||
## Contributing
|
||||
|
||||
All code contributions - including those of people having commit access - must go through a pull request and approved by a core developer before being merged. This is to ensure proper review of all the code.
|
||||
All code contributions - including those of people having commit access - must go through a pull request and be approved by a core developer before being merged. This is to ensure a proper review of all the code.
|
||||
|
||||
We truly ❤️ pull requests! If you wish to help, you can learn more about how you can contribute to this project in the [contribution guide](CONTRIBUTING.md).
|
||||
|
||||
## Security
|
||||
|
||||
For security issues, kindly email us at [security@appwrite.io](mailto:security@appwrite.io) instead of posting a public issue in GitHub.
|
||||
For security issues, kindly email us at [security@appwrite.io](mailto:security@appwrite.io) instead of posting a public issue on GitHub.
|
||||
|
||||
## Follow Us
|
||||
|
||||
|
|
|
@ -255,17 +255,17 @@ return [
|
|||
'variables' => [
|
||||
[
|
||||
'name' => '_APP_SMTP_HOST',
|
||||
'description' => 'SMTP server host name address. Default value is: \'smtp\'. Pass an empty string to disable all mail sending from the server.',
|
||||
'description' => 'SMTP server host name address. Use an empty string to disable all mail sending from the server. The default value for this variable is an empty string',
|
||||
'introduction' => '',
|
||||
'default' => 'smtp',
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_PORT',
|
||||
'description' => 'SMTP server TCP port. Default value is: \'25\'.',
|
||||
'description' => 'SMTP server TCP port. Empty by default.',
|
||||
'introduction' => '',
|
||||
'default' => '25',
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\Exception;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Appwrite\Resize\Resize;
|
||||
use Appwrite\URL\URL as URLParse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Validator\HexColor;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\QROptions;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Exception;
|
||||
use Utopia\Image\Image;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\HexColor;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
$avatarCallback = function ($type, $code, $width, $height, $quality, $response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
||||
$code = \strtolower($code);
|
||||
$type = \strtolower($type);
|
||||
$set = Config::getParam('avatar-'.$type, []);
|
||||
$set = Config::getParam('avatar-' . $type, []);
|
||||
|
||||
if (empty($set)) {
|
||||
throw new Exception('Avatar set not found', 404);
|
||||
|
@ -37,17 +37,17 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response)
|
|||
}
|
||||
|
||||
$output = 'png';
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
|
||||
$key = \md5('/v1/avatars/:type/:code-'.$code.$width.$height.$quality.$output);
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
|
||||
$key = \md5('/v1/avatars/:type/:code-' . $code . $width . $height . $quality . $output);
|
||||
$path = $set[$code];
|
||||
$type = 'png';
|
||||
|
||||
if (!\is_readable($path)) {
|
||||
throw new Exception('File not readable in '.$path, 500);
|
||||
throw new Exception('File not readable in ' . $path, 500);
|
||||
}
|
||||
|
||||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE.'/app-0')); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
|
||||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE . '/app-0')); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3/* 3 months */);
|
||||
|
||||
if ($data) {
|
||||
//$output = (empty($output)) ? $type : $output;
|
||||
|
@ -60,24 +60,23 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response)
|
|||
;
|
||||
}
|
||||
|
||||
$resize = new Resize(\file_get_contents($path));
|
||||
$image = new Image(\file_get_contents($path));
|
||||
|
||||
$resize->crop((int) $width, (int) $height);
|
||||
$image->crop((int) $width, (int) $height);
|
||||
|
||||
$output = (empty($output)) ? $type : $output;
|
||||
|
||||
$data = $resize->output($output, $quality);
|
||||
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$cache->save($key, $data);
|
||||
|
||||
|
||||
$response
|
||||
->setContentType('image/png')
|
||||
->addHeader('Expires', $date)
|
||||
->addHeader('X-Appwrite-Cache', 'miss')
|
||||
->send($data, null);
|
||||
;
|
||||
|
||||
unset($resize);
|
||||
unset($image);
|
||||
};
|
||||
|
||||
App::get('/v1/avatars/credit-cards/:code')
|
||||
|
@ -91,7 +90,7 @@ App::get('/v1/avatars/credit-cards/:code')
|
|||
->label('sdk.description', '/docs/references/avatars/get-credit-card.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
|
||||
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.')
|
||||
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.')
|
||||
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
|
||||
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
|
||||
->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
|
||||
|
@ -160,11 +159,11 @@ App::get('/v1/avatars/image')
|
|||
|
||||
$quality = 80;
|
||||
$output = 'png';
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
|
||||
$key = \md5('/v2/avatars/images-'.$url.'-'.$width.'/'.$height.'/'.$quality);
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
|
||||
$key = \md5('/v2/avatars/images-' . $url . '-' . $width . '/' . $height . '/' . $quality);
|
||||
$type = 'png';
|
||||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE.'/app-0')); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 7 /* 1 week */);
|
||||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE . '/app-0')); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 7/* 1 week */);
|
||||
|
||||
if ($data) {
|
||||
return $response
|
||||
|
@ -186,17 +185,17 @@ App::get('/v1/avatars/image')
|
|||
}
|
||||
|
||||
try {
|
||||
$resize = new Resize($fetch);
|
||||
} catch (\Exception $exception) {
|
||||
$image = new Image($fetch);
|
||||
} catch (\Exception$exception) {
|
||||
throw new Exception('Unable to parse image', 500);
|
||||
}
|
||||
|
||||
$resize->crop((int) $width, (int) $height);
|
||||
$image->crop((int) $width, (int) $height);
|
||||
|
||||
$output = (empty($output)) ? $type : $output;
|
||||
|
||||
$data = $resize->output($output, $quality);
|
||||
|
||||
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$cache->save($key, $data);
|
||||
|
||||
$response
|
||||
|
@ -206,7 +205,7 @@ App::get('/v1/avatars/image')
|
|||
->send($data);
|
||||
;
|
||||
|
||||
unset($resize);
|
||||
unset($image);
|
||||
});
|
||||
|
||||
App::get('/v1/avatars/favicon')
|
||||
|
@ -229,11 +228,11 @@ App::get('/v1/avatars/favicon')
|
|||
$height = 56;
|
||||
$quality = 80;
|
||||
$output = 'png';
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
|
||||
$key = \md5('/v2/avatars/favicon-'.$url);
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
|
||||
$key = \md5('/v2/avatars/favicon-' . $url);
|
||||
$type = 'png';
|
||||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE.'/app-0')); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
|
||||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE . '/app-0')); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3/* 3 months */);
|
||||
|
||||
if ($data) {
|
||||
return $response
|
||||
|
@ -316,7 +315,7 @@ App::get('/v1/avatars/favicon')
|
|||
if (empty($outputHref) || empty($outputExt)) {
|
||||
$default = \parse_url($url);
|
||||
|
||||
$outputHref = $default['scheme'].'://'.$default['host'].'/favicon.ico';
|
||||
$outputHref = $default['scheme'] . '://' . $default['host'] . '/favicon.ico';
|
||||
$outputExt = 'ico';
|
||||
}
|
||||
|
||||
|
@ -343,13 +342,13 @@ App::get('/v1/avatars/favicon')
|
|||
throw new Exception('Icon not found', 404);
|
||||
}
|
||||
|
||||
$resize = new Resize($fetch);
|
||||
$image = new Image($fetch);
|
||||
|
||||
$resize->crop((int) $width, (int) $height);
|
||||
$image->crop((int) $width, (int) $height);
|
||||
|
||||
$output = (empty($output)) ? $type : $output;
|
||||
|
||||
$data = $resize->output($output, $quality);
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$cache->save($key, $data);
|
||||
|
||||
|
@ -359,7 +358,7 @@ App::get('/v1/avatars/favicon')
|
|||
->addHeader('X-Appwrite-Cache', 'miss')
|
||||
->send($data);
|
||||
|
||||
unset($resize);
|
||||
unset($image);
|
||||
});
|
||||
|
||||
App::get('/v1/avatars/qr')
|
||||
|
@ -394,14 +393,14 @@ App::get('/v1/avatars/qr')
|
|||
$response->addHeader('Content-Disposition', 'attachment; filename="qr.png"');
|
||||
}
|
||||
|
||||
$resize = new Resize($qrcode->render($text));
|
||||
$image = new Image($qrcode->render($text));
|
||||
|
||||
$resize->crop((int) $size, (int) $size);
|
||||
$image->crop((int) $size, (int) $size);
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->send($resize->output('png', 9))
|
||||
->send($image->output('png', 9))
|
||||
;
|
||||
});
|
||||
|
||||
|
@ -437,10 +436,10 @@ App::get('/v1/avatars/initials')
|
|||
['color' => '#610038', 'background' => '#f5d1e6'], // PINK
|
||||
['color' => '#386100', 'background' => '#dcf1bd'], // LIME
|
||||
['color' => '#615800', 'background' => '#f1ecba'], // YELLOW
|
||||
['color' => '#610008', 'background' => '#f6d2d5'] // RED
|
||||
['color' => '#610008', 'background' => '#f6d2d5'], // RED
|
||||
];
|
||||
|
||||
$rand = \rand(0, \count($themes)-1);
|
||||
$rand = \rand(0, \count($themes) - 1);
|
||||
|
||||
$name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
|
||||
$words = \explode(' ', \strtoupper($name));
|
||||
|
@ -457,23 +456,23 @@ App::get('/v1/avatars/initials')
|
|||
}
|
||||
|
||||
$length = \count($words);
|
||||
$rand = \substr($code,-1);
|
||||
$background = (!empty($background)) ? '#'.$background : $themes[$rand]['background'];
|
||||
$color = (!empty($color)) ? '#'.$color : $themes[$rand]['color'];
|
||||
$rand = \substr($code, -1);
|
||||
$background = (!empty($background)) ? '#' . $background : $themes[$rand]['background'];
|
||||
$color = (!empty($color)) ? '#' . $color : $themes[$rand]['color'];
|
||||
|
||||
$image = new \Imagick();
|
||||
$draw = new \ImagickDraw();
|
||||
$fontSize = \min($width, $height) / 2;
|
||||
|
||||
$draw->setFont(__DIR__."/../../../public/fonts/poppins-v9-latin-500.ttf");
|
||||
$image->setFont(__DIR__."/../../../public/fonts/poppins-v9-latin-500.ttf");
|
||||
|
||||
$draw->setFont(__DIR__ . "/../../../public/fonts/poppins-v9-latin-500.ttf");
|
||||
$image->setFont(__DIR__ . "/../../../public/fonts/poppins-v9-latin-500.ttf");
|
||||
|
||||
$draw->setFillColor(new \ImagickPixel($color));
|
||||
$draw->setFontSize($fontSize);
|
||||
|
||||
|
||||
$draw->setTextAlignment(\Imagick::ALIGN_CENTER);
|
||||
$draw->annotation($width / 1.97, ($height / 2) + ($fontSize / 3), $initials);
|
||||
|
||||
|
||||
$image->newImage($width, $height, $background);
|
||||
$image->setImageFormat("png");
|
||||
$image->drawImage($draw);
|
||||
|
@ -481,7 +480,7 @@ App::get('/v1/avatars/initials')
|
|||
//$image->setImageCompressionQuality(9 - round(($quality / 100) * 9));
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->send($image->getImageBlob())
|
||||
;
|
||||
|
|
|
@ -294,7 +294,7 @@ App::put('/v1/functions/:functionId')
|
|||
}
|
||||
|
||||
$original = $function->getAttribute('schedule', '');
|
||||
$cron = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? CronExpression::factory($schedule) : null;
|
||||
$cron = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : null;
|
||||
|
||||
$function = $projectDB->updateDocument(array_merge($function->getArrayCopy(), [
|
||||
|
@ -359,7 +359,7 @@ App::patch('/v1/functions/:functionId/tag')
|
|||
}
|
||||
|
||||
$schedule = $function->getAttribute('schedule', '');
|
||||
$cron = (empty($function->getAttribute('tag')) && !empty($schedule)) ? CronExpression::factory($schedule) : null;
|
||||
$cron = (empty($function->getAttribute('tag')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('tag')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : null;
|
||||
|
||||
$function = $projectDB->updateDocument(array_merge($function->getArrayCopy(), [
|
||||
|
|
|
@ -943,7 +943,7 @@ App::post('/v1/projects/:projectId/tasks')
|
|||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
$cron = CronExpression::factory($schedule);
|
||||
$cron = new CronExpression($schedule);
|
||||
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
|
||||
|
||||
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
|
||||
|
@ -1093,7 +1093,7 @@ App::put('/v1/projects/:projectId/tasks/:taskId')
|
|||
throw new Exception('Task not found', 404);
|
||||
}
|
||||
|
||||
$cron = CronExpression::factory($schedule);
|
||||
$cron = new CronExpression($schedule);
|
||||
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
|
||||
|
||||
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
|
||||
|
|
|
@ -18,7 +18,7 @@ use Utopia\Storage\Validator\File;
|
|||
use Utopia\Storage\Validator\FileSize;
|
||||
use Utopia\Storage\Validator\Upload;
|
||||
use Utopia\Storage\Compression\Algorithms\GZIP;
|
||||
use Appwrite\Resize\Resize;
|
||||
use Utopia\Image\Image;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
|
@ -332,17 +332,17 @@ App::get('/v1/storage/files/:fileId/preview')
|
|||
$source = $compressor->decompress($source);
|
||||
}
|
||||
|
||||
$resize = new Resize($source);
|
||||
$image = new Image($source);
|
||||
|
||||
$resize->crop((int) $width, (int) $height);
|
||||
$image->crop((int) $width, (int) $height);
|
||||
|
||||
if (!empty($background)) {
|
||||
$resize->setBackground('#'.$background);
|
||||
$image->setBackground('#'.$background);
|
||||
}
|
||||
|
||||
$output = (empty($output)) ? $type : $output;
|
||||
|
||||
$data = $resize->output($output, $quality);
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$cache->save($key, $data);
|
||||
|
||||
|
@ -353,7 +353,7 @@ App::get('/v1/storage/files/:fileId/preview')
|
|||
->send($data)
|
||||
;
|
||||
|
||||
unset($resize);
|
||||
unset($image);
|
||||
});
|
||||
|
||||
App::get('/v1/storage/files/:fileId/download')
|
||||
|
|
|
@ -144,6 +144,7 @@ App::get('/console/settings')
|
|||
$page
|
||||
->setParam('customDomainsEnabled', ($target->isKnown() && !$target->isTest()))
|
||||
->setParam('customDomainsTarget', $target->get())
|
||||
->setParam('smtpEnabled', (!empty(App::getEnv('_APP_SMTP_HOST'))))
|
||||
;
|
||||
|
||||
$layout
|
||||
|
|
|
@ -375,4 +375,40 @@ App::get('/specs/:format')
|
|||
|
||||
$response
|
||||
->json($specs->parse());
|
||||
});
|
||||
|
||||
App::get('/versions')
|
||||
->desc('Get Version')
|
||||
->groups(['web', 'home'])
|
||||
->label('scope', 'public')
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
||||
$platforms = Config::getParam('platforms');
|
||||
|
||||
$versions = [
|
||||
'server' => APP_VERSION_STABLE,
|
||||
];
|
||||
|
||||
foreach($platforms as $platform) {
|
||||
$languages = $platform['languages'] ?? [];
|
||||
|
||||
foreach ($languages as $key => $language) {
|
||||
if(isset($language['dev']) && $language['dev']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isset($language['enabled']) && !$language['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$platformKey = $platform['key'] ?? '';
|
||||
$languageKey = $language['key'] ?? '';
|
||||
$version = $language['version'] ?? '';
|
||||
$versions[$platformKey . '-' . $languageKey] = $version;
|
||||
}
|
||||
}
|
||||
|
||||
$response->json($versions);
|
||||
});
|
|
@ -139,7 +139,6 @@ $cli
|
|||
Console::success('SMTP................connected 👍');
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('SMTP.............disconnected 👎');
|
||||
var_dump($th);
|
||||
}
|
||||
|
||||
$host = App::getEnv('_APP_STATSD_HOST', 'telegraf');
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
</td>
|
||||
<td data-title="Size: ">
|
||||
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileSize}}"></span>
|
||||
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileUnit}}"></span>
|
||||
</td>
|
||||
<td data-title="Created: ">
|
||||
<span class="text-fade text-size-small" data-ls-bind="{{file.dateCreated|dateText}}"></span>
|
||||
|
|
|
@ -117,7 +117,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
<b data-ls-bind="{{tag.$id}}"></b>
|
||||
<span class="text-fade" data-ls-bind="{{tag.command}}"></span>
|
||||
<div class="text-size-small margin-top-small clear">
|
||||
<span class="pull-start" data-ls-bind="Created {{tag.dateCreated|timeSince}} | {{tag.size|humanFileSize}}"></span>
|
||||
<span class="pull-start" data-ls-bind="Created {{tag.dateCreated|timeSince}} | {{tag.size|humanFileSize}}{{tag.size|humanFileUnit}}"></span>
|
||||
|
||||
<form data-ls-if="{{tag.$id}} !== {{project-function.tag}}" name="functions.deleteTag" class="pull-start"
|
||||
data-analytics
|
||||
|
|
|
@ -97,7 +97,10 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
</div>
|
||||
</div>
|
||||
<div class="col span-3">
|
||||
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.network.total|humanFileSize}}" data-default="0">0</span></div>
|
||||
<div class="value margin-bottom-small">
|
||||
<span class="sum" data-ls-bind="{{usage.network.total|humanFileSize}}" data-default="0">0</span>
|
||||
<span data-ls-bind="{{usage.network.total|humanFileUnit}}" class="text-size-small unit"></span>
|
||||
</div>
|
||||
<div class="metric margin-bottom-small">Bandwidth</div>
|
||||
|
||||
<div class="margin-top-large value small">
|
||||
|
@ -117,7 +120,10 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
<div class="margin-top-small"><b class="text-size-small unit">Documents</b></div>
|
||||
</div>
|
||||
<div class="col span-3">
|
||||
<div class="value"><span class="sum" data-ls-bind="{{usage.storage.total|humanFileSize}}" data-default="0">0</span></div>
|
||||
<div class="value">
|
||||
<span class="sum" data-ls-bind="{{usage.storage.total|humanFileSize}}" data-default="0">0</span>
|
||||
<span data-ls-bind="{{usage.storage.total|humanFileUnit}}" class="text-size-small unit"></span>
|
||||
</div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Storage</b></div>
|
||||
</div>
|
||||
<div class="col span-3">
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
$customDomainsEnabled = $this->getParam('customDomainsEnabled', false);
|
||||
$customDomainsTarget = $this->getParam('customDomainsTarget', false);
|
||||
$smtpEnabled = $this->getParam('smtpEnabled', false);
|
||||
|
||||
?>
|
||||
<div class="cover">
|
||||
|
@ -506,10 +507,16 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false);
|
|||
<option data-ls-attrs="value={{role.type}}" data-ls-bind="{{role.label}}"></option>
|
||||
</select>
|
||||
|
||||
<?php if(!$smtpEnabled): ?>
|
||||
<div class="box note padding-tiny warning margin-bottom text-align-center">
|
||||
<i class="icon-warning"></i> SMTP connection is disabled. <a href="https://appwrite.io/docs/email-delivery" target="_blank" rel="noopener">Learn more <i class="icon-link-ext"></i></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="clear">
|
||||
<button>Send Invite</button>
|
||||
<button<?php if(!$smtpEnabled): ?> disabled<?php endif; ?>>Send Invite</button>
|
||||
<button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -204,6 +204,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
|||
</td>
|
||||
<td data-title="Size: ">
|
||||
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileSize}}"></span>
|
||||
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileUnit}}"></span>
|
||||
</td>
|
||||
<td data-title="Created: ">
|
||||
<span class="text-fade text-size-small" data-ls-bind="{{file.dateCreated|dateText}}"></span>
|
||||
|
|
|
@ -56,9 +56,12 @@ services:
|
|||
- influxdb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_CONSOLE_WHITELIST_EMAILS
|
||||
- _APP_CONSOLE_WHITELIST_IPS
|
||||
- _APP_SYSTEM_EMAIL_NAME
|
||||
- _APP_SYSTEM_EMAIL_ADDRESS
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_SYSTEM_RESPONSE_FORMAT
|
||||
- _APP_OPTIONS_ABUSE
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
|
@ -273,7 +276,6 @@ services:
|
|||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- smtp
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_SYSTEM_EMAIL_NAME
|
||||
|
@ -340,16 +342,6 @@ services:
|
|||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
command: 'mysqld --innodb-flush-method=fsync'
|
||||
|
||||
smtp:
|
||||
image: appwrite/smtp:1.0.1
|
||||
container_name: appwrite-smtp
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
environment:
|
||||
- MAILNAME=appwrite
|
||||
- RELAY_NETWORKS=:192.168.0.0/24:10.0.0.0/16
|
||||
|
||||
redis:
|
||||
image: redis:6.0-alpine3.12
|
||||
container_name: appwrite-redis
|
||||
|
|
|
@ -227,7 +227,7 @@ class FunctionsV1
|
|||
return;
|
||||
}
|
||||
|
||||
$cron = CronExpression::factory($function->getAttribute('schedule'));
|
||||
$cron = new CronExpression($function->getAttribute('schedule'));
|
||||
$next = (int) $cron->getNextRunDate()->format('U');
|
||||
|
||||
$function
|
||||
|
|
|
@ -82,7 +82,7 @@ class TasksV1
|
|||
|
||||
// Reschedule
|
||||
|
||||
$cron = CronExpression::factory($task->getAttribute('schedule'));
|
||||
$cron = new CronExpression($task->getAttribute('schedule'));
|
||||
$next = (int) $cron->getNextRunDate()->format('U');
|
||||
$headers = (\is_array($task->getAttribute('httpHeaders', []))) ? $task->getAttribute('httpHeaders', []) : [];
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
"utopia-php/analytics": "0.1.*",
|
||||
"utopia-php/audit": "0.5.*",
|
||||
"utopia-php/cache": "0.2.*",
|
||||
"utopia-php/cli": "0.9.0",
|
||||
"utopia-php/cli": "0.10.0",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/locale": "0.3.*",
|
||||
"utopia-php/registry": "0.2.*",
|
||||
|
@ -47,16 +47,17 @@
|
|||
"utopia-php/domains": "0.2.*",
|
||||
"utopia-php/swoole": "0.2.*",
|
||||
"utopia-php/system": "0.4.*",
|
||||
"utopia-php/storage": "0.2.*",
|
||||
"utopia-php/storage": "0.4.*",
|
||||
"utopia-php/image": "0.1.*",
|
||||
|
||||
"resque/php-resque": "1.3.6",
|
||||
"matomo/device-detector": "3.13.0",
|
||||
"dragonmantank/cron-expression": "3.0.1",
|
||||
"matomo/device-detector": "4.1.0",
|
||||
"dragonmantank/cron-expression": "3.1.0",
|
||||
"domnikl/statsd": "3.0.2",
|
||||
"influxdb/influxdb-php": "1.15.1",
|
||||
"phpmailer/phpmailer": "6.1.7",
|
||||
"influxdb/influxdb-php": "1.15.2",
|
||||
"phpmailer/phpmailer": "6.3.0",
|
||||
"chillerlan/php-qrcode": "4.3.0",
|
||||
"adhocore/jwt": "1.1.0"
|
||||
"adhocore/jwt": "1.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"appwrite/sdk-generator": "0.5.5",
|
||||
|
|
322
composer.lock
generated
|
@ -8,20 +8,20 @@
|
|||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/adhocore/php-jwt.git",
|
||||
"reference": "424a1d66b729a316dd074e6382167765b810cd3d"
|
||||
"reference": "6c434af7170090bb7a8880d2bc220a2254ba7899"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/adhocore/php-jwt/zipball/424a1d66b729a316dd074e6382167765b810cd3d",
|
||||
"reference": "424a1d66b729a316dd074e6382167765b810cd3d",
|
||||
"url": "https://api.github.com/repos/adhocore/php-jwt/zipball/6c434af7170090bb7a8880d2bc220a2254ba7899",
|
||||
"reference": "6c434af7170090bb7a8880d2bc220a2254ba7899",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0"
|
||||
"php": "^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.5 || ^7.5"
|
||||
|
@ -53,7 +53,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/adhocore/php-jwt/issues",
|
||||
"source": "https://github.com/adhocore/php-jwt/tree/1.1.0"
|
||||
"source": "https://github.com/adhocore/php-jwt/tree/1.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -61,7 +61,7 @@
|
|||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-09T00:34:35+00:00"
|
||||
"time": "2021-02-20T09:56:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "appwrite/php-clamav",
|
||||
|
@ -354,27 +354,30 @@
|
|||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
"version": "3.0.1",
|
||||
"version": "v3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dragonmantank/cron-expression.git",
|
||||
"reference": "fa4e95ff5a7f1d62c3fbc05c32729b7f3ca14b52"
|
||||
"reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/fa4e95ff5a7f1d62c3fbc05c32729b7f3ca14b52",
|
||||
"reference": "fa4e95ff5a7f1d62c3fbc05c32729b7f3ca14b52",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c",
|
||||
"reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
"php": "^7.2|^8.0",
|
||||
"webmozart/assert": "^1.7.0"
|
||||
},
|
||||
"replace": {
|
||||
"mtdowling/cron-expression": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^0.11",
|
||||
"phpunit/phpunit": "^6.4|^7.0"
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpstan/phpstan-webmozart-assert": "^0.12.7",
|
||||
"phpunit/phpunit": "^7.0|^8.0|^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -400,7 +403,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dragonmantank/cron-expression/issues",
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/3.0.1"
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -408,7 +411,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-08-21T02:30:13+00:00"
|
||||
"time": "2020-11-24T19:55:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
|
@ -645,24 +648,25 @@
|
|||
},
|
||||
{
|
||||
"name": "influxdb/influxdb-php",
|
||||
"version": "1.15.1",
|
||||
"version": "1.15.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/influxdata/influxdb-php.git",
|
||||
"reference": "447acb600969f9510c9f1900a76d442fc3537b0e"
|
||||
"reference": "d6e59f4f04ab9107574fda69c2cbe36671253d03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/influxdata/influxdb-php/zipball/447acb600969f9510c9f1900a76d442fc3537b0e",
|
||||
"reference": "447acb600969f9510c9f1900a76d442fc3537b0e",
|
||||
"url": "https://api.github.com/repos/influxdata/influxdb-php/zipball/d6e59f4f04ab9107574fda69c2cbe36671253d03",
|
||||
"reference": "d6e59f4f04ab9107574fda69c2cbe36671253d03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^6.0|^7.0",
|
||||
"php": "^5.5 || ^7.0"
|
||||
"php": "^5.5 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
"dms/phpunit-arraysubset-asserts": "^0.2.1",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "Curl extension, needed for Curl driver",
|
||||
|
@ -704,34 +708,39 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/influxdata/influxdb-php/issues",
|
||||
"source": "https://github.com/influxdata/influxdb-php/tree/1.15.1"
|
||||
"source": "https://github.com/influxdata/influxdb-php/tree/1.15.2"
|
||||
},
|
||||
"time": "2020-09-18T13:24:03+00:00"
|
||||
"time": "2020-12-26T17:45:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "matomo/device-detector",
|
||||
"version": "3.13.0",
|
||||
"version": "4.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/matomo-org/device-detector.git",
|
||||
"reference": "75ca5b690e38c40d199ade93e677bc5d7c3bc498"
|
||||
"reference": "6b3facc35e7a465bc4223fddfa5fa88c5b327554"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/75ca5b690e38c40d199ade93e677bc5d7c3bc498",
|
||||
"reference": "75ca5b690e38c40d199ade93e677bc5d7c3bc498",
|
||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/6b3facc35e7a465bc4223fddfa5fa88c5b327554",
|
||||
"reference": "6b3facc35e7a465bc4223fddfa5fa88c5b327554",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"mustangostang/spyc": "*",
|
||||
"php": ">=5.5"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"replace": {
|
||||
"piwik/device-detector": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"fabpot/php-cs-fixer": "~1.7",
|
||||
"matthiasmullie/scrapbook": "@stable",
|
||||
"phpunit/phpunit": "^4.8.36",
|
||||
"psr/cache": "^1.0",
|
||||
"psr/simple-cache": "^1.0"
|
||||
"matthiasmullie/scrapbook": "^1.4.7",
|
||||
"mayflower/mo4-coding-standard": "dev-master#275cb9d",
|
||||
"phpstan/phpstan": "^0.12.52",
|
||||
"phpunit/phpunit": "^8.5.8",
|
||||
"psr/cache": "^1.0.1",
|
||||
"psr/simple-cache": "^1.0.1",
|
||||
"symfony/yaml": "^5.1.7"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/cache": "Can directly be used for caching purpose",
|
||||
|
@ -741,7 +750,10 @@
|
|||
"autoload": {
|
||||
"psr-4": {
|
||||
"DeviceDetector\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
|
@ -767,7 +779,7 @@
|
|||
"source": "https://github.com/matomo-org/piwik",
|
||||
"wiki": "https://dev.matomo.org/"
|
||||
},
|
||||
"time": "2020-08-17T07:37:33+00:00"
|
||||
"time": "2021-01-08T14:14:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mustangostang/spyc",
|
||||
|
@ -821,27 +833,31 @@
|
|||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v6.1.7",
|
||||
"version": "v6.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0"
|
||||
"reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0",
|
||||
"reference": "2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb",
|
||||
"reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-hash": "*",
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"doctrine/annotations": "^1.2",
|
||||
"friendsofphp/php-cs-fixer": "^2.2",
|
||||
"phpunit/phpunit": "^4.8 || ^5.7"
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.5.6",
|
||||
"yoast/phpunit-polyfills": "^0.2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset",
|
||||
|
@ -881,15 +897,15 @@
|
|||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.1.7"
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/synchro",
|
||||
"url": "https://github.com/Synchro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T18:50:27+00:00"
|
||||
"time": "2021-02-19T15:28:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-client",
|
||||
|
@ -1176,6 +1192,86 @@
|
|||
},
|
||||
"time": "2020-04-16T16:39:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "dev-main",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
|
||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.22-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-07T16:49:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.3.1",
|
||||
|
@ -1389,16 +1485,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/cli",
|
||||
"version": "0.9.0",
|
||||
"version": "0.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/cli.git",
|
||||
"reference": "a83f8b5f57022e0d1c50913f1b1ab4f8f087dceb"
|
||||
"reference": "69ae40187fb4b68ef14f0224a68d9cc016b83634"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/cli/zipball/a83f8b5f57022e0d1c50913f1b1ab4f8f087dceb",
|
||||
"reference": "a83f8b5f57022e0d1c50913f1b1ab4f8f087dceb",
|
||||
"url": "https://api.github.com/repos/utopia-php/cli/zipball/69ae40187fb4b68ef14f0224a68d9cc016b83634",
|
||||
"reference": "69ae40187fb4b68ef14f0224a68d9cc016b83634",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1436,9 +1532,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cli/issues",
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.9.0"
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.10.0"
|
||||
},
|
||||
"time": "2021-01-19T20:00:02+00:00"
|
||||
"time": "2021-01-26T16:35:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/config",
|
||||
|
@ -1595,6 +1691,59 @@
|
|||
},
|
||||
"time": "2020-12-26T12:02:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
"version": "0.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/image.git",
|
||||
"reference": "66e38db211b1d6fe93de09d82606641e0f996e42"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/image/zipball/66e38db211b1d6fe93de09d82606641e0f996e42",
|
||||
"reference": "66e38db211b1d6fe93de09d82606641e0f996e42",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"chillerlan/php-qrcode": "4.3.0",
|
||||
"ext-imagick": "*",
|
||||
"php": ">=7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"vimeo/psalm": "4.0.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Image\\": "src/Image"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eldad Fux",
|
||||
"email": "eldad@appwrite.io"
|
||||
}
|
||||
],
|
||||
"description": "A simple Image manipulation library",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"image",
|
||||
"php",
|
||||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/image/issues",
|
||||
"source": "https://github.com/utopia-php/image/tree/0.1.0"
|
||||
},
|
||||
"time": "2021-02-19T05:09:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/locale",
|
||||
"version": "0.3.3",
|
||||
|
@ -1753,16 +1902,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/storage",
|
||||
"version": "0.2.0",
|
||||
"version": "0.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/storage.git",
|
||||
"reference": "27bfd663c9b2a17ac0911522a87f42bee834df95"
|
||||
"reference": "86f749f2d79268528732e560f77dde0155e162ca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/27bfd663c9b2a17ac0911522a87f42bee834df95",
|
||||
"reference": "27bfd663c9b2a17ac0911522a87f42bee834df95",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/86f749f2d79268528732e560f77dde0155e162ca",
|
||||
"reference": "86f749f2d79268528732e560f77dde0155e162ca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1799,9 +1948,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/storage/issues",
|
||||
"source": "https://github.com/utopia-php/storage/tree/0.2.0"
|
||||
"source": "https://github.com/utopia-php/storage/tree/0.4.1"
|
||||
},
|
||||
"time": "2021-01-27T12:21:27+00:00"
|
||||
"time": "2021-02-19T05:04:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/swoole",
|
||||
|
@ -1913,6 +2062,65 @@
|
|||
"source": "https://github.com/utopia-php/system/tree/0.4.0"
|
||||
},
|
||||
"time": "2021-02-04T14:14:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozarts/assert.git",
|
||||
"reference": "9c89b265ccc4092d58e66d72af5d343ee77a41ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/9c89b265ccc4092d58e66d72af5d343ee77a41ae",
|
||||
"reference": "9c89b265ccc4092d58e66d72af5d343ee77a41ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan": "<0.12.20",
|
||||
"vimeo/psalm": "<3.9.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.13"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webmozart\\Assert\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Assertions to validate method input/output with nice error messages.",
|
||||
"keywords": [
|
||||
"assert",
|
||||
"check",
|
||||
"validate"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/webmozarts/assert/issues",
|
||||
"source": "https://github.com/webmozarts/assert/tree/master"
|
||||
},
|
||||
"time": "2021-01-18T12:52:36+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
|
13
public/dist/scripts/app-all.js
vendored
|
@ -2071,7 +2071,7 @@ container.path(paths[i],value);}});}
|
|||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
else{if(element.textContent!=value){element.textContent=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
|
@ -2250,9 +2250,10 @@ return value+" "+unit+" "+direction;}).add("ms2hum",function($value){let temp=$v
|
|||
(minutes?minutes+"m ":"")+
|
||||
Number.parseFloat(seconds).toFixed(0)+"s");}
|
||||
return"< 1s";}).add("seconds2hum",function($value){var seconds=($value).toFixed(3);var minutes=($value/(60)).toFixed(1);var hours=($value/(60*60)).toFixed(1);var days=($value/(60*60*24)).toFixed(1);if(seconds<60){return seconds+"s";}else if(minutes<60){return minutes+"m";}else if(hours<24){return hours+"h";}else{return days+"d"}}).add("markdown",function($value,markdown){return markdown.render($value);}).add("pageCurrent",function($value,env){return Math.ceil(parseInt($value||0)/env.PAGING_LIMIT)+1;}).add("pageTotal",function($value,env){let total=Math.ceil(parseInt($value||0)/env.PAGING_LIMIT);return total?total:1;}).add("humanFileSize",function($value){if(!$value){return 0;}
|
||||
let thresh=1000;if(Math.abs($value)<thresh){return $value+" B";}
|
||||
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return($value.toFixed(1)+'<span class="text-size-small unit">'+
|
||||
units[u]+"</span>");}).add("statsTotal",function($value){if(!$value){return 0;}
|
||||
let thresh=1000;if(Math.abs($value)<thresh){return $value;}
|
||||
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return $value.toFixed(1);}).add("humanFileUnit",function($value){if(!$value){return'';}
|
||||
let thresh=1000;if(Math.abs($value)<thresh){return'B';}
|
||||
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return units[u];}).add("statsTotal",function($value){if(!$value){return 0;}
|
||||
$value=abbreviate($value,0,false,false);return $value==="0"?"N/A":$value;}).add("isEmpty",function($value){return(!!$value);}).add("isEmptyObject",function($value){return((Object.keys($value).length===0&&$value.constructor===Object)||$value.length===0)}).add("activeDomainsCount",function($value){let result=[];if(Array.isArray($value)){result=$value.filter(function(node){return(node.verification&&node.certificateId);});}
|
||||
return result.length;}).add("documentAction",function(container){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&!document.$id){return'database.createDocument';}
|
||||
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
|
||||
|
@ -2305,8 +2306,8 @@ parsedFailure[i].slice(1),{}));}
|
|||
element.$lsSkip=false;view.render(element);});};let events=event.trim().split(",");for(let y=0;y<events.length;y++){if(""===events[y]){continue;}
|
||||
switch(events[y].trim()){case"load":exec();break;case"none":break;case"click":case"change":case"keypress":case"keydown":case"keyup":case"input":case"submit":element.addEventListener(events[y],exec);break;default:document.addEventListener(events[y],exec);}}}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics",controller:function(element){let action=element.getAttribute("data-analytics-event")||"click";let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
element.addEventListener(action,function(){let category=element.getAttribute("data-analytics-category")||"undefined";let label=element.getAttribute("data-analytics-label")||"undefined";if(!ga){console.error("Google Analytics ga object is not available");}
|
||||
ga("send",{hitType:"event",eventCategory:category,eventAction:action,eventLabel:label});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-activity",controller:function(window,element,appwrite,account){let action=element.getAttribute("data-analytics-event")||"click";let activity=element.getAttribute("data-analytics-label")||"None";let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
element.addEventListener(action,function(){let email=account?.email||element.elements['email'].value||'';appwrite.analytics.create(email,'console',activity,window.location.href)});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-pageview",controller:function(window,router,env){if(!ga){console.error("Google Analytics ga object is not available");}
|
||||
ga("send",{hitType:"event",eventCategory:category,eventAction:action,eventLabel:label});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-activity",controller:function(window,element,appwrite,container){let action=element.getAttribute("data-analytics-event")||"click";let activity=element.getAttribute("data-analytics-label")||"None";let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
element.addEventListener(action,function(){let account=container.get('account');let email=account?.email||element?.elements['email']?.value||'';appwrite.analytics.create(email,'console',activity,window.location.href)});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-pageview",controller:function(window,router,env){if(!ga){console.error("Google Analytics ga object is not available");}
|
||||
let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
let project=router.params["project"]||'None';ga("set","page",window.location.pathname);ga("set","dimension1",project);ga('set','dimension2',env.VERSION);ga('set','dimension3',env.SETUP);ga("send","pageview");}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-clone",controller:function(element,document,view){var template=element.innerHTML.toString();var label=element.dataset["label"]||"Add";var icon=element.dataset["icon"]||null;var target=element.dataset["target"]||null;var first=parseInt(element.dataset["first"]||1);var button=document.createElement("button");button.type="button";button.innerText=" "+label+" ";button.classList.add("margin-end");button.classList.add("margin-bottom-small");button.classList.add("reverse");if(icon){var iconElement=document.createElement("i");iconElement.className=icon;button.insertBefore(iconElement,button.firstChild);}
|
||||
if(target){target=document.getElementById(target);}
|
||||
|
|
13
public/dist/scripts/app.js
vendored
|
@ -116,7 +116,7 @@ container.path(paths[i],value);}});}
|
|||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
else{if(element.textContent!=value){element.textContent=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
|
@ -295,9 +295,10 @@ return value+" "+unit+" "+direction;}).add("ms2hum",function($value){let temp=$v
|
|||
(minutes?minutes+"m ":"")+
|
||||
Number.parseFloat(seconds).toFixed(0)+"s");}
|
||||
return"< 1s";}).add("seconds2hum",function($value){var seconds=($value).toFixed(3);var minutes=($value/(60)).toFixed(1);var hours=($value/(60*60)).toFixed(1);var days=($value/(60*60*24)).toFixed(1);if(seconds<60){return seconds+"s";}else if(minutes<60){return minutes+"m";}else if(hours<24){return hours+"h";}else{return days+"d"}}).add("markdown",function($value,markdown){return markdown.render($value);}).add("pageCurrent",function($value,env){return Math.ceil(parseInt($value||0)/env.PAGING_LIMIT)+1;}).add("pageTotal",function($value,env){let total=Math.ceil(parseInt($value||0)/env.PAGING_LIMIT);return total?total:1;}).add("humanFileSize",function($value){if(!$value){return 0;}
|
||||
let thresh=1000;if(Math.abs($value)<thresh){return $value+" B";}
|
||||
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return($value.toFixed(1)+'<span class="text-size-small unit">'+
|
||||
units[u]+"</span>");}).add("statsTotal",function($value){if(!$value){return 0;}
|
||||
let thresh=1000;if(Math.abs($value)<thresh){return $value;}
|
||||
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return $value.toFixed(1);}).add("humanFileUnit",function($value){if(!$value){return'';}
|
||||
let thresh=1000;if(Math.abs($value)<thresh){return'B';}
|
||||
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return units[u];}).add("statsTotal",function($value){if(!$value){return 0;}
|
||||
$value=abbreviate($value,0,false,false);return $value==="0"?"N/A":$value;}).add("isEmpty",function($value){return(!!$value);}).add("isEmptyObject",function($value){return((Object.keys($value).length===0&&$value.constructor===Object)||$value.length===0)}).add("activeDomainsCount",function($value){let result=[];if(Array.isArray($value)){result=$value.filter(function(node){return(node.verification&&node.certificateId);});}
|
||||
return result.length;}).add("documentAction",function(container){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&!document.$id){return'database.createDocument';}
|
||||
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
|
||||
|
@ -350,8 +351,8 @@ parsedFailure[i].slice(1),{}));}
|
|||
element.$lsSkip=false;view.render(element);});};let events=event.trim().split(",");for(let y=0;y<events.length;y++){if(""===events[y]){continue;}
|
||||
switch(events[y].trim()){case"load":exec();break;case"none":break;case"click":case"change":case"keypress":case"keydown":case"keyup":case"input":case"submit":element.addEventListener(events[y],exec);break;default:document.addEventListener(events[y],exec);}}}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics",controller:function(element){let action=element.getAttribute("data-analytics-event")||"click";let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
element.addEventListener(action,function(){let category=element.getAttribute("data-analytics-category")||"undefined";let label=element.getAttribute("data-analytics-label")||"undefined";if(!ga){console.error("Google Analytics ga object is not available");}
|
||||
ga("send",{hitType:"event",eventCategory:category,eventAction:action,eventLabel:label});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-activity",controller:function(window,element,appwrite,account){let action=element.getAttribute("data-analytics-event")||"click";let activity=element.getAttribute("data-analytics-label")||"None";let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
element.addEventListener(action,function(){let email=account?.email||element.elements['email'].value||'';appwrite.analytics.create(email,'console',activity,window.location.href)});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-pageview",controller:function(window,router,env){if(!ga){console.error("Google Analytics ga object is not available");}
|
||||
ga("send",{hitType:"event",eventCategory:category,eventAction:action,eventLabel:label});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-activity",controller:function(window,element,appwrite,container){let action=element.getAttribute("data-analytics-event")||"click";let activity=element.getAttribute("data-analytics-label")||"None";let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
element.addEventListener(action,function(){let account=container.get('account');let email=account?.email||element?.elements['email']?.value||'';appwrite.analytics.create(email,'console',activity,window.location.href)});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-analytics-pageview",controller:function(window,router,env){if(!ga){console.error("Google Analytics ga object is not available");}
|
||||
let doNotTrack=window.navigator.doNotTrack;if(doNotTrack=='1'){return;}
|
||||
let project=router.params["project"]||'None';ga("set","page",window.location.pathname);ga("set","dimension1",project);ga('set','dimension2',env.VERSION);ga('set','dimension3',env.SETUP);ga("send","pageview");}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-clone",controller:function(element,document,view){var template=element.innerHTML.toString();var label=element.dataset["label"]||"Add";var icon=element.dataset["icon"]||null;var target=element.dataset["target"]||null;var first=parseInt(element.dataset["first"]||1);var button=document.createElement("button");button.type="button";button.innerText=" "+label+" ";button.classList.add("margin-end");button.classList.add("margin-bottom-small");button.classList.add("reverse");if(icon){var iconElement=document.createElement("i");iconElement.className=icon;button.insertBefore(iconElement,button.firstChild);}
|
||||
if(target){target=document.getElementById(target);}
|
||||
|
|
2
public/dist/styles/default-ltr.css
vendored
2
public/dist/styles/default-rtl.css
vendored
|
@ -116,7 +116,7 @@ container.path(paths[i],value);}});}
|
|||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
else{if(element.textContent!=value){element.textContent=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
|
|
|
@ -133,7 +133,7 @@ window.ls.filter
|
|||
let thresh = 1000;
|
||||
|
||||
if (Math.abs($value) < thresh) {
|
||||
return $value + " B";
|
||||
return $value;
|
||||
}
|
||||
|
||||
let units = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
|
@ -144,12 +144,28 @@ window.ls.filter
|
|||
++u;
|
||||
} while (Math.abs($value) >= thresh && u < units.length - 1);
|
||||
|
||||
return (
|
||||
$value.toFixed(1) +
|
||||
'<span class="text-size-small unit">' +
|
||||
units[u] +
|
||||
"</span>"
|
||||
);
|
||||
return $value.toFixed(1);
|
||||
})
|
||||
.add("humanFileUnit", function($value) {
|
||||
if (!$value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let thresh = 1000;
|
||||
|
||||
if (Math.abs($value) < thresh) {
|
||||
return 'B';
|
||||
}
|
||||
|
||||
let units = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
let u = -1;
|
||||
|
||||
do {
|
||||
$value /= thresh;
|
||||
++u;
|
||||
} while (Math.abs($value) >= thresh && u < units.length - 1);
|
||||
|
||||
return units[u];
|
||||
})
|
||||
.add("statsTotal", function($value) {
|
||||
if (!$value) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
window.ls.container.get("view").add({
|
||||
selector: "data-analytics-activity",
|
||||
controller: function(window, element, appwrite, account) {
|
||||
controller: function(window, element, appwrite, container) {
|
||||
let action = element.getAttribute("data-analytics-event") || "click";
|
||||
let activity = element.getAttribute("data-analytics-label") || "None";
|
||||
let doNotTrack = window.navigator.doNotTrack;
|
||||
|
@ -13,8 +13,9 @@
|
|||
}
|
||||
|
||||
element.addEventListener(action, function() {
|
||||
let email = account?.email || element.elements['email'].value || '';
|
||||
|
||||
let account = container.get('account');
|
||||
let email = account?.email || element?.elements['email']?.value || '';
|
||||
|
||||
appwrite.analytics.create(email, 'console', activity, window.location.href)
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
display: block;
|
||||
border-bottom: none;
|
||||
|
||||
&.padding-tiny {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
&.padding-xs {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&.padding-small {
|
||||
padding: 15px;
|
||||
}
|
||||
|
@ -53,7 +61,7 @@
|
|||
}
|
||||
|
||||
&.warning {
|
||||
background: var(--config-color-success);
|
||||
background: var(--config-color-warning);
|
||||
color: #2d2d2d;
|
||||
|
||||
button,
|
||||
|
|
|
@ -53,6 +53,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.padding-tiny {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
&.padding-xs {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&.padding-small {
|
||||
padding: 15px;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
--config-color-fade-super: #f1f3f5;
|
||||
--config-color-danger: #f53d3d;
|
||||
--config-color-success: #1bbf61;
|
||||
--config-color-warning: #ffed4d;
|
||||
--config-color-warning: #fffbdd;
|
||||
--config-color-info: #386fd2;
|
||||
--config-border-color: #f3f3f3;
|
||||
--config-border-fade: #e0e3e4;
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Resize;
|
||||
|
||||
use Exception;
|
||||
use Imagick;
|
||||
|
||||
class Resize
|
||||
{
|
||||
private $image;
|
||||
|
||||
private $width;
|
||||
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->image = new Imagick();
|
||||
|
||||
$this->image->readImageBlob($data);
|
||||
|
||||
$this->width = $this->image->getImageWidth();
|
||||
$this->height = $this->image->getImageHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
*
|
||||
* @return Resize
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function crop(int $width, int $height)
|
||||
{
|
||||
$originalAspect = $this->width / $this->height;
|
||||
|
||||
if (empty($width)) {
|
||||
$width = $height * $originalAspect;
|
||||
}
|
||||
|
||||
if (empty($height)) {
|
||||
$height = $width / $originalAspect;
|
||||
}
|
||||
|
||||
if (empty($height) && empty($width)) {
|
||||
$height = $this->height;
|
||||
$width = $this->width;
|
||||
}
|
||||
|
||||
if ($this->image->getImageFormat() == 'GIF') {
|
||||
$this->image = $this->image->coalesceImages();
|
||||
|
||||
foreach ($this->image as $frame) {
|
||||
$frame->cropThumbnailImage($width, $height);
|
||||
}
|
||||
|
||||
$this->image->deconstructImages();
|
||||
} else {
|
||||
$this->image->cropThumbnailImage($width, $height);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $color
|
||||
*
|
||||
* @return Resize
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function setBackground($color)
|
||||
{
|
||||
$this->image->setImageBackgroundColor($color);
|
||||
$this->image = $this->image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output.
|
||||
*
|
||||
* Prints manipulated image.
|
||||
*
|
||||
* @param string $type
|
||||
* @param int $quality
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function output(string $type, int $quality = 75)
|
||||
{
|
||||
return $this->save(null, $type, $quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param $type
|
||||
* @param int $quality
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function save(string $path = null, string $type = '', int $quality = 75)
|
||||
{
|
||||
// Create directory with write permissions
|
||||
if (null !== $path && !\file_exists(\dirname($path))) {
|
||||
if (!@\mkdir(\dirname($path), 0755, true)) {
|
||||
throw new Exception('Can\'t create directory '.\dirname($path));
|
||||
}
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
$this->image->setImageCompressionQuality($quality);
|
||||
|
||||
$this->image->setImageFormat('jpg');
|
||||
break;
|
||||
|
||||
case 'gif':
|
||||
$this->image->setImageFormat('gif');
|
||||
break;
|
||||
|
||||
case 'webp':
|
||||
try {
|
||||
$this->image->setImageFormat('webp');
|
||||
} catch (\Throwable $th) {
|
||||
$signature = $this->image->getImageSignature();
|
||||
$temp = '/tmp/temp-'.$signature.'.'.\strtolower($this->image->getImageFormat());
|
||||
$output = '/tmp/output-'.$signature.'.webp';
|
||||
|
||||
// save temp
|
||||
$this->image->writeImages($temp, true);
|
||||
|
||||
// convert temp
|
||||
\exec("cwebp -quiet -metadata none -q $quality $temp -o $output");
|
||||
|
||||
$data = \file_get_contents($output);
|
||||
|
||||
//load webp
|
||||
if (empty($path)) {
|
||||
return $data;
|
||||
} else {
|
||||
\file_put_contents($path, $data, LOCK_EX);
|
||||
}
|
||||
|
||||
$this->image->clear();
|
||||
$this->image->destroy();
|
||||
|
||||
//delete webp
|
||||
\unlink($output);
|
||||
\unlink($temp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'png':
|
||||
/* Scale quality from 0-100 to 0-9 */
|
||||
$scaleQuality = \round(($quality / 100) * 9);
|
||||
|
||||
/* Invert quality setting as 0 is best, not 9 */
|
||||
$invertScaleQuality = 9 - $scaleQuality;
|
||||
|
||||
$this->image->setImageCompressionQuality($invertScaleQuality);
|
||||
|
||||
$this->image->setImageFormat('png');
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Invalid output type given');
|
||||
break;
|
||||
}
|
||||
|
||||
if (empty($path)) {
|
||||
return $this->image->getImagesBlob();
|
||||
} else {
|
||||
$this->image->writeImages($path, true);
|
||||
}
|
||||
|
||||
$this->image->clear();
|
||||
$this->image->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $newHeight
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getSizeByFixedHeight(int $newHeight):int
|
||||
{
|
||||
$ratio = $this->width / $this->height;
|
||||
$newWidth = $newHeight * $ratio;
|
||||
|
||||
return $newWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $newWidth
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getSizeByFixedWidth(int $newWidth):int
|
||||
{
|
||||
$ratio = $this->height / $this->width;
|
||||
$newHeight = $newWidth * $ratio;
|
||||
|
||||
return $newHeight;
|
||||
}
|
||||
}
|
|
@ -186,4 +186,27 @@ class HTTPTest extends Scope
|
|||
$this->assertEquals($body['continents']['AN'], 'Antarctica');
|
||||
$this->assertEquals($body['continents']['AS'], 'Asia');
|
||||
}
|
||||
|
||||
public function testVersions() {
|
||||
|
||||
/**
|
||||
* Test without header
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/versions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$body = $response['body'];
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertIsString($body['server']);
|
||||
$this->assertIsString($body['client-web']);
|
||||
$this->assertIsString($body['client-flutter']);
|
||||
$this->assertIsString($body['console-web']);
|
||||
$this->assertIsString($body['server-nodejs']);
|
||||
$this->assertIsString($body['server-deno']);
|
||||
$this->assertIsString($body['server-php']);
|
||||
$this->assertIsString($body['server-python']);
|
||||
$this->assertIsString($body['server-ruby']);
|
||||
$this->assertIsString($body['server-cli']);
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 799 B |
Before Width: | Height: | Size: 596 KiB |
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -38,7 +38,7 @@ class DetectorTest extends TestCase
|
|||
'clientName' => 'Firefox',
|
||||
'clientVersion' => '47.0',
|
||||
'clientEngine' => 'Gecko',
|
||||
'clientEngineVersion' => '',
|
||||
'clientEngineVersion' => '47.0',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Tests;
|
||||
|
||||
use Appwrite\Resize\Resize;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ResizeTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function testCrop100x100()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'));
|
||||
$target = __DIR__.'/100x100.jpg';
|
||||
|
||||
$resize->crop(100, 100);
|
||||
|
||||
$resize->save($target, 'jpg', 100);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
$this->assertEquals(100, $image->getImageWidth());
|
||||
$this->assertEquals(100, $image->getImageHeight());
|
||||
$this->assertEquals('JPEG', $image->getImageFormat());
|
||||
|
||||
\unlink($target);
|
||||
}
|
||||
|
||||
public function testCrop100x400()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'));
|
||||
$target = __DIR__.'/100x400.jpg';
|
||||
|
||||
$resize->crop(100, 400);
|
||||
|
||||
$resize->save($target, 'jpg', 100);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
$this->assertEquals(100, $image->getImageWidth());
|
||||
$this->assertEquals(400, $image->getImageHeight());
|
||||
$this->assertEquals('JPEG', $image->getImageFormat());
|
||||
|
||||
\unlink($target);
|
||||
}
|
||||
|
||||
public function testCrop400x100()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'));
|
||||
$target = __DIR__.'/400x100.jpg';
|
||||
|
||||
$resize->crop(400, 100);
|
||||
|
||||
$resize->save($target, 'jpg', 100);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
$this->assertEquals(400, $image->getImageWidth());
|
||||
$this->assertEquals(100, $image->getImageHeight());
|
||||
$this->assertEquals('JPEG', $image->getImageFormat());
|
||||
|
||||
\unlink($target);
|
||||
}
|
||||
|
||||
public function testCrop100x100WEBP()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'));
|
||||
$target = __DIR__.'/100x100.webp';
|
||||
$original = __DIR__.'/../../resources/resize/100x100.webp';
|
||||
|
||||
$resize->crop(100, 100);
|
||||
|
||||
$resize->save($target, 'webp', 100);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
|
||||
$this->assertEquals(100, $image->getImageWidth());
|
||||
$this->assertEquals(100, $image->getImageHeight());
|
||||
$this->assertTrue(in_array($image->getImageFormat(), ['PAM', 'WEBP']));
|
||||
|
||||
\unlink($target);
|
||||
}
|
||||
|
||||
public function testCrop100x100PNG()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'));
|
||||
$target = __DIR__.'/100x100.png';
|
||||
$original = __DIR__.'/../../resources/resize/100x100.png';
|
||||
|
||||
$resize->crop(100, 100);
|
||||
|
||||
$resize->save($target, 'png', 100);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertGreaterThan(15000, \filesize($target));
|
||||
$this->assertLessThan(30000, \filesize($target));
|
||||
$this->assertEquals(\mime_content_type($target), \mime_content_type($original));
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
$this->assertEquals(100, $image->getImageWidth());
|
||||
$this->assertEquals(100, $image->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
|
||||
\unlink($target);
|
||||
}
|
||||
|
||||
public function testCrop100x100PNGQuality30()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'));
|
||||
$target = __DIR__.'/100x100-q30.jpg';
|
||||
$original = __DIR__.'/../../resources/resize/100x100-q30.jpg';
|
||||
|
||||
$resize->crop(100, 100);
|
||||
|
||||
$resize->save($target, 'jpg', 10);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertGreaterThan(500, \filesize($target));
|
||||
$this->assertLessThan(2000, \filesize($target));
|
||||
$this->assertEquals(\mime_content_type($target), \mime_content_type($original));
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
$this->assertEquals(100, $image->getImageWidth());
|
||||
$this->assertEquals(100, $image->getImageHeight());
|
||||
$this->assertEquals('JPEG', $image->getImageFormat());
|
||||
|
||||
\unlink($target);
|
||||
}
|
||||
|
||||
public function testCrop100x100GIF()
|
||||
{
|
||||
$resize = new Resize(\file_get_contents(__DIR__ . '/../../resources/disk-a/kitten-3.gif'));
|
||||
$target = __DIR__.'/100x100.gif';
|
||||
$original = __DIR__.'/../../resources/resize/100x100.gif';
|
||||
|
||||
$resize->crop(100, 100);
|
||||
|
||||
$resize->save($target, 'gif', 100);
|
||||
|
||||
$this->assertEquals(\is_readable($target), true);
|
||||
$this->assertGreaterThan(400000, \filesize($target));
|
||||
$this->assertLessThan(800000, \filesize($target));
|
||||
$this->assertEquals(\mime_content_type($target), \mime_content_type($original));
|
||||
$this->assertNotEmpty(\md5(\file_get_contents($target)));
|
||||
|
||||
$image = new \Imagick($target);
|
||||
$this->assertEquals(100, $image->getImageWidth());
|
||||
$this->assertEquals(100, $image->getImageHeight());
|
||||
$this->assertEquals('GIF', $image->getImageFormat());
|
||||
\unlink($target);
|
||||
}
|
||||
}
|