Merge pull request #9417 from appwrite/feat-screenshot-task
Feat: Screenshot task for templates
|
|
@ -68,6 +68,7 @@ RUN chmod +x /usr/local/bin/doctor && \
|
|||
chmod +x /usr/local/bin/sdks && \
|
||||
chmod +x /usr/local/bin/specs && \
|
||||
chmod +x /usr/local/bin/ssl && \
|
||||
chmod +x /usr/local/bin/screenshot && \
|
||||
chmod +x /usr/local/bin/test && \
|
||||
chmod +x /usr/local/bin/upgrade && \
|
||||
chmod +x /usr/local/bin/vars && \
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ return [
|
|||
'key' => 'template-for-onelink',
|
||||
'name' => 'Onelink template',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/template-for-onelink.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/template-for-onelink-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/template-for-onelink-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NUXT', [
|
||||
'providerRootDirectory' => './onelink',
|
||||
|
|
@ -140,7 +141,8 @@ return [
|
|||
'key' => 'starter-for-svelte',
|
||||
'name' => 'Svelte starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/starter-for-svelte.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-svelte-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-svelte-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('SVELTEKIT', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -181,7 +183,8 @@ return [
|
|||
'key' => 'starter-for-react',
|
||||
'name' => 'React starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/starter-for-react.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-react-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-react-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('REACT', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -222,7 +225,8 @@ return [
|
|||
'key' => 'starter-for-vue',
|
||||
'name' => 'Vue starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/starter-for-vue.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-vue-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-vue-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('VUE', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -263,7 +267,8 @@ return [
|
|||
'key' => 'starter-for-react-native',
|
||||
'name' => 'React Native starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/starter-for-react-native.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-react-native-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-react-native-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('REACT', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -305,7 +310,8 @@ return [
|
|||
'key' => 'starter-for-nextjs',
|
||||
'name' => 'Next.js starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/starter-for-nextjs.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-nextjs-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-nextjs-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NEXTJS', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -346,7 +352,8 @@ return [
|
|||
'key' => 'starter-for-nuxt',
|
||||
'name' => 'Nuxt starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/starter-for-nuxt.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-nuxt-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-nuxt-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NUXT', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -387,7 +394,8 @@ return [
|
|||
'key' => 'template-for-event',
|
||||
'name' => 'Event template',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/template-for-event.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/template-for-event-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/template-for-event-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NEXTJS', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -422,7 +430,8 @@ return [
|
|||
'key' => 'template-for-portfolio',
|
||||
'name' => 'Portfolio template',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/template-for-portfolio.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/template-for-portfolio-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/template-for-portfolio-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NEXTJS', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -438,7 +447,8 @@ return [
|
|||
'key' => 'template-for-store',
|
||||
'name' => 'Store template',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/template-for-store.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/template-for-store-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/template-for-store-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('SVELTEKIT', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -479,7 +489,8 @@ return [
|
|||
'key' => 'template-for-blog',
|
||||
'name' => 'Blog template',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => $url . '/console/images/sites/templates/template-for-blog.png',
|
||||
'screenshotDark' => $url . '/images/sites/templates/template-for-blog-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/template-for-blog-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('SVELTEKIT', [
|
||||
'providerRootDirectory' => './',
|
||||
|
|
@ -495,7 +506,8 @@ return [
|
|||
'key' => 'astro-starter',
|
||||
'name' => 'Astro starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => '',
|
||||
'screenshotDark' => $url . '/images/sites/templates/astro-starter-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/astro-starter-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('ASTRO', [
|
||||
'providerRootDirectory' => './astro/starter',
|
||||
|
|
@ -511,7 +523,8 @@ return [
|
|||
'key' => 'remix-starter',
|
||||
'name' => 'Remix starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => '',
|
||||
'screenshotDark' => $url . '/images/sites/templates/remix-starter-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/remix-starter-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('REMIX', [
|
||||
'providerRootDirectory' => './remix/starter',
|
||||
|
|
@ -527,7 +540,8 @@ return [
|
|||
'key' => 'flutter-starter',
|
||||
'name' => 'Flutter starter',
|
||||
'useCases' => ['starter'],
|
||||
'demoImage' => '',
|
||||
'screenshotDark' => $url . '/images/sites/templates/flutter-starter-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/flutter-starter-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('FLUTTER', [
|
||||
'providerRootDirectory' => './flutter/starter',
|
||||
|
|
@ -543,6 +557,8 @@ return [
|
|||
'key' => 'nextjs-starter',
|
||||
'name' => 'Next.js starter website',
|
||||
'useCases' => ['starter'],
|
||||
'screenshotDark' => $url . '/images/sites/templates/nextjs-starter-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/nextjs-starter-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NEXTJS', [
|
||||
'providerRootDirectory' => './nextjs/starter',
|
||||
|
|
@ -558,6 +574,8 @@ return [
|
|||
'key' => 'nuxt-starter',
|
||||
'name' => 'Nuxt starter website',
|
||||
'useCases' => ['starter'],
|
||||
'screenshotDark' => $url . '/images/sites/templates/nuxt-starter-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/nuxt-starter-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NUXT', [
|
||||
'providerRootDirectory' => './nuxt/starter',
|
||||
|
|
@ -573,6 +591,8 @@ return [
|
|||
'key' => 'sveltekit-starter',
|
||||
'name' => 'SvelteKit starter website',
|
||||
'useCases' => ['starter'],
|
||||
'screenshotDark' => $url . '/images/sites/templates/sveltekit-starter-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/sveltekit-starter-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('SVELTEKIT', [
|
||||
'providerRootDirectory' => './sveltekit/starter',
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ use Utopia\Pools\Group;
|
|||
use Utopia\Swoole\Files;
|
||||
use Utopia\System\System;
|
||||
|
||||
Files::load(__DIR__.'/../public');
|
||||
|
||||
const DOMAIN_SYNC_TIMER = 30; // 30 seconds
|
||||
|
||||
$domains = new Table(1_000_000); // 1 million rows
|
||||
|
|
|
|||
|
|
@ -1977,6 +1977,7 @@ App::setResource('previewHostname', function (Request $request, ?Key $apiKey) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return '';
|
||||
}, ['request', 'apiKey']);
|
||||
|
||||
|
|
|
|||
3
bin/screenshot
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
php /usr/src/code/app/cli.php screenshot $@
|
||||
|
|
@ -953,7 +953,7 @@ services:
|
|||
|
||||
appwrite-browser:
|
||||
container_name: appwrite-browser
|
||||
image: appwrite/browser:0.2.0
|
||||
image: appwrite/browser:0.2.1
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
|
|
|
|||
BIN
public/images/sites/templates/astro-starter-dark.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
public/images/sites/templates/astro-starter-light.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
public/images/sites/templates/flutter-starter-dark.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/sites/templates/flutter-starter-light.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/sites/templates/nextjs-starter-dark.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/images/sites/templates/nextjs-starter-light.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/images/sites/templates/nuxt-starter-dark.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
public/images/sites/templates/nuxt-starter-light.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
public/images/sites/templates/remix-starter-dark.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
public/images/sites/templates/remix-starter-light.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
public/images/sites/templates/starter-for-nextjs-dark.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
public/images/sites/templates/starter-for-nextjs-light.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
public/images/sites/templates/starter-for-nuxt-dark.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
public/images/sites/templates/starter-for-nuxt-light.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
public/images/sites/templates/starter-for-react-dark.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
public/images/sites/templates/starter-for-react-light.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
public/images/sites/templates/starter-for-svelte-dark.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/images/sites/templates/starter-for-svelte-light.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/images/sites/templates/starter-for-vue-dark.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
public/images/sites/templates/starter-for-vue-light.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
public/images/sites/templates/sveltekit-starter-dark.png
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
public/images/sites/templates/sveltekit-starter-light.png
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
public/images/sites/templates/template-for-blog-dark.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
public/images/sites/templates/template-for-blog-light.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
public/images/sites/templates/template-for-event-dark.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/images/sites/templates/template-for-event-light.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/images/sites/templates/template-for-onelink-dark.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
public/images/sites/templates/template-for-onelink-light.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
public/images/sites/templates/template-for-portfolio-dark.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
public/images/sites/templates/template-for-portfolio-light.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
public/images/sites/templates/template-for-store-dark.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
public/images/sites/templates/template-for-store-light.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
|
|
@ -740,6 +740,7 @@ class Builds extends Action
|
|||
}
|
||||
|
||||
$client = new FetchClient();
|
||||
$client->setTimeout(\intval($resource->getAttribute('timeout', '15')));
|
||||
$client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON);
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots'));
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Appwrite\Platform\Tasks\QueueRetry;
|
|||
use Appwrite\Platform\Tasks\ScheduleExecutions;
|
||||
use Appwrite\Platform\Tasks\ScheduleFunctions;
|
||||
use Appwrite\Platform\Tasks\ScheduleMessages;
|
||||
use Appwrite\Platform\Tasks\Screenshot;
|
||||
use Appwrite\Platform\Tasks\SDKs;
|
||||
use Appwrite\Platform\Tasks\Specs;
|
||||
use Appwrite\Platform\Tasks\SSL;
|
||||
|
|
@ -32,6 +33,7 @@ class Tasks extends Service
|
|||
->addAction(QueueRetry::getName(), new QueueRetry())
|
||||
->addAction(SDKs::getName(), new SDKs())
|
||||
->addAction(SSL::getName(), new SSL())
|
||||
->addAction(Screenshot::getName(), new Screenshot())
|
||||
->addAction(ScheduleFunctions::getName(), new ScheduleFunctions())
|
||||
->addAction(ScheduleExecutions::getName(), new ScheduleExecutions())
|
||||
->addAction(ScheduleMessages::getName(), new ScheduleMessages())
|
||||
|
|
|
|||
300
src/Appwrite/Platform/Tasks/Screenshot.php
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Tasks;
|
||||
|
||||
use Appwrite\ID;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Screenshot extends Action
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'screenshot';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->desc('Create Site template screenshot')
|
||||
->param('templateId', '', new Text(128), 'Template ID.')
|
||||
->callback(fn (string $templateId) => $this->action($templateId));
|
||||
}
|
||||
|
||||
public function action(string $templateId): void
|
||||
{
|
||||
$templates = Config::getParam('site-templates', []);
|
||||
|
||||
$allowedTemplates = \array_filter($templates, function ($item) use ($templateId) {
|
||||
return $item['key'] === $templateId;
|
||||
});
|
||||
$template = \array_shift($allowedTemplates);
|
||||
|
||||
if (empty($template)) {
|
||||
throw new \Exception("Template {$templateId} not found. Find correct ID in app/config/site-templates.php");
|
||||
}
|
||||
|
||||
Console::info("Found: " . $template['name']);
|
||||
|
||||
$client = new Client();
|
||||
$client->setEndpoint('http://localhost/v1');
|
||||
$client->addHeader('origin', 'http://localhost');
|
||||
|
||||
// Register
|
||||
$email = uniqid() . 'user@localhost.test';
|
||||
$password = 'password';
|
||||
$user = $client->call(Client::METHOD_POST, '/account', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
], [
|
||||
'userId' => ID::unique(),
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
if ($user['headers']['status-code'] !== 201) {
|
||||
Console::error(\json_encode($user));
|
||||
throw new \Exception("Failed to register user");
|
||||
}
|
||||
|
||||
Console::info("User created");
|
||||
|
||||
// Login
|
||||
$session = $client->call(Client::METHOD_POST, '/account/sessions/email', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
], [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
if ($session['headers']['status-code'] !== 201) {
|
||||
Console::error(\json_encode($session));
|
||||
throw new \Exception("Failed to login user");
|
||||
}
|
||||
|
||||
Console::info("Session created");
|
||||
|
||||
$secret = $session['cookies']['a_session_console'];
|
||||
$cookieConsole = 'a_session_console=' . $secret;
|
||||
|
||||
// Create organization
|
||||
$team = $client->call(Client::METHOD_POST, '/teams', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
'cookie' => $cookieConsole
|
||||
], [
|
||||
'teamId' => ID::unique(),
|
||||
'name' => 'Demo Project Team',
|
||||
]);
|
||||
|
||||
if ($team['headers']['status-code'] !== 201) {
|
||||
Console::error(\json_encode($team));
|
||||
throw new \Exception("Failed to create team");
|
||||
}
|
||||
|
||||
Console::info("Team created");
|
||||
|
||||
$projectName = 'Demo Project';
|
||||
$projectId = ID::unique();
|
||||
|
||||
// Create project
|
||||
$project = $client->call(Client::METHOD_POST, '/projects', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
'cookie' => $cookieConsole
|
||||
], [
|
||||
'projectId' => $projectId,
|
||||
'region' => 'default',
|
||||
'name' => $projectName,
|
||||
'teamId' => $team['body']['$id'],
|
||||
'description' => 'Demo Project Description',
|
||||
'url' => 'https://appwrite.io',
|
||||
]);
|
||||
|
||||
if ($project['headers']['status-code'] !== 201) {
|
||||
Console::error(\json_encode($project));
|
||||
throw new \Exception("Failed to create project");
|
||||
}
|
||||
|
||||
Console::info("Project created");
|
||||
|
||||
$projectId = $project['body']['$id'];
|
||||
|
||||
$framework = $template['frameworks'][0];
|
||||
|
||||
// Create site
|
||||
$site = $client->call(Client::METHOD_POST, '/sites', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => $cookieConsole
|
||||
], [
|
||||
'siteId' => ID::unique(),
|
||||
'name' => $template["name"],
|
||||
'framework' => $framework['key'],
|
||||
'adapter' => $framework['adapter'],
|
||||
'buildCommand' => $framework['buildCommand'],
|
||||
'buildRuntime' => $framework['buildRuntime'],
|
||||
'fallbackFile' => $framework['fallbackFile'],
|
||||
'installCommand' => $framework['installCommand'],
|
||||
'outputDirectory' => $framework['outputDirectory'],
|
||||
'providerRootDirectory' => $framework['providerRootDirectory'],
|
||||
'timeout' => 60
|
||||
]);
|
||||
|
||||
if ($site['headers']['status-code'] !== 201) {
|
||||
Console::error(\json_encode($site));
|
||||
throw new \Exception("Failed to create site");
|
||||
}
|
||||
|
||||
Console::info("Site created");
|
||||
|
||||
$siteId = $site['body']['$id'];
|
||||
|
||||
// Create variables
|
||||
if (!empty($template['variables'] ?? [])) {
|
||||
foreach ($template['variables'] as $variable) {
|
||||
if (empty($variable['value'] ?? '')) {
|
||||
if (($variable['required'] ?? false) === true) {
|
||||
throw new \Exception("Missing required variable: {$variable['name']}");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $variable['value'];
|
||||
$value = \str_replace('{projectName}', $projectName, $value);
|
||||
$value = \str_replace('{projectId}', $projectId, $value);
|
||||
$value = \str_replace('{apiEndpoint}', 'http://localhost/v1', $value);
|
||||
|
||||
$response = $client->call(Client::METHOD_POST, '/sites/' . $siteId . '/variables', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => $cookieConsole
|
||||
], [
|
||||
'key' => $variable['name'],
|
||||
'value' => $value
|
||||
]);
|
||||
|
||||
if ($response['headers']['status-code'] !== 201) {
|
||||
Console::error(\json_encode($response));
|
||||
throw new \Exception("Failed to create variable");
|
||||
}
|
||||
}
|
||||
|
||||
Console::info("Variables created");
|
||||
}
|
||||
|
||||
// Create deployment
|
||||
$deployment = $client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments/template', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => $cookieConsole
|
||||
], [
|
||||
'owner' => $template['providerOwner'],
|
||||
'repository' => $template['providerRepositoryId'],
|
||||
'rootDirectory' => $framework['providerRootDirectory'],
|
||||
'version' => $template['providerVersion'],
|
||||
'activate' => true,
|
||||
]);
|
||||
|
||||
if ($deployment['headers']['status-code'] !== 202) {
|
||||
Console::error(\json_encode($deployment));
|
||||
throw new \Exception("Failed to create deployment");
|
||||
}
|
||||
|
||||
Console::info("Deployment created");
|
||||
|
||||
$deploymentId = $deployment['body']['$id'];
|
||||
|
||||
// Await screenshot
|
||||
$attempts = 50;
|
||||
$sleep = 5;
|
||||
|
||||
$idLight = '';
|
||||
$idDark = '';
|
||||
|
||||
Console::log("Awaiting deployment (every $sleep seconds, $attempts attempts)");
|
||||
|
||||
for ($i = 0; $i < $attempts; $i++) {
|
||||
$deployment = $client->call(Client::METHOD_GET, '/sites/' . $siteId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => $cookieConsole
|
||||
]);
|
||||
|
||||
if ($deployment['headers']['status-code'] !== 200) {
|
||||
Console::error(\json_encode($deployment));
|
||||
throw new \Exception("Failed to get deployment");
|
||||
}
|
||||
|
||||
if ($deployment['body']['status'] === 'failed') {
|
||||
Console::error(\json_encode($deployment));
|
||||
throw new \Exception("Deployment build failed");
|
||||
}
|
||||
|
||||
if ($deployment['body']['status'] !== 'ready') {
|
||||
Console::log("Deployment not ready yet, status: " . $deployment['body']['status']);
|
||||
\sleep($sleep);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (empty($deployment['body']['screenshotLight'])) {
|
||||
Console::log("Light screenshot not available yet");
|
||||
\sleep($sleep);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($deployment['body']['screenshotDark'])) {
|
||||
Console::log("Dark screenshot not available yet");
|
||||
\sleep($sleep);
|
||||
continue;
|
||||
}
|
||||
|
||||
$idLight = $deployment['body']['screenshotLight'];
|
||||
$idDark = $deployment['body']['screenshotDark'];
|
||||
break;
|
||||
}
|
||||
|
||||
if (empty($idLight) || empty($idDark)) {
|
||||
Console::error(\json_encode($deployment));
|
||||
throw new \Exception("Failed to get deployment screenshot");
|
||||
}
|
||||
|
||||
Console::info("Screenshots created");
|
||||
|
||||
$themes = [
|
||||
[ 'fileId' => $idLight, 'suffix' => 'light' ],
|
||||
[ 'fileId' => $idDark, 'suffix' => 'dark' ]
|
||||
];
|
||||
|
||||
foreach ($themes as $theme) {
|
||||
$file = $client->call(Client::METHOD_GET, '/storage/buckets/screenshots/files/' . $theme['fileId'] . '/download', [
|
||||
'x-appwrite-project' => 'console',
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => $cookieConsole
|
||||
]);
|
||||
|
||||
if ($file['headers']['status-code'] !== 200) {
|
||||
Console::error(\json_encode($file));
|
||||
throw new \Exception("Failed to download {$theme['suffix']} screenshot");
|
||||
}
|
||||
|
||||
$path = "/usr/src/code/public/images/sites/templates/{$template['key']}-{$theme['suffix']}.png";
|
||||
|
||||
if (!\file_put_contents($path, $file['body'])) {
|
||||
throw new \Exception("Failed to save {$theme['suffix']} screenshot");
|
||||
}
|
||||
}
|
||||
|
||||
Console::success("Screenshots saved");
|
||||
}
|
||||
}
|
||||
|
|
@ -28,11 +28,17 @@ class TemplateSite extends Model
|
|||
'default' => '',
|
||||
'example' => 'https://nextjs-starter.appwrite.network/',
|
||||
])
|
||||
->addRule('demoImage', [
|
||||
->addRule('screenshotDark', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'File URL with preview screenshot.',
|
||||
'description' => 'File URL with preview screenshot in dark theme preference.',
|
||||
'default' => '',
|
||||
'example' => 'https://cloud.appwrite.io/console/images/sites/templates/nextjs-starter.png',
|
||||
'example' => 'https://cloud.appwrite.io/images/sites/templates/template-for-blog-dark.png',
|
||||
])
|
||||
->addRule('screenshotLight', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'File URL with preview screenshot in light theme preference.',
|
||||
'default' => '',
|
||||
'example' => 'https://cloud.appwrite.io/images/sites/templates/template-for-blog-light.png',
|
||||
])
|
||||
->addRule('useCases', [
|
||||
'type' => self::TYPE_STRING,
|
||||
|
|
|
|||