diff --git a/README.md b/README.md index b97ef99..66934dc 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,17 @@ -Symfony Standard Edition -======================== -Welcome to the Symfony Standard Edition - a fully-functional Symfony2 -application that you can use as the skeleton for your new applications. -For details on how to download and get started with Symfony, see the -[Installation][1] chapter of the Symfony Documentation. +```shell +npm install -g less +``` -What's inside? --------------- +... -The Symfony Standard Edition is configured with the following defaults: +```shell +php app/console braincrafted:bootstrap:install +``` - * An AppBundle you can use to start coding; +... - * Twig as the only configured template engine; - - * Doctrine ORM/DBAL; - - * Swiftmailer; - - * Annotations enabled for everything. - -It comes pre-configured with the following bundles: - - * **FrameworkBundle** - The core Symfony framework bundle - - * [**SensioFrameworkExtraBundle**][6] - Adds several enhancements, including - template and routing annotation capability - - * [**DoctrineBundle**][7] - Adds support for the Doctrine ORM - - * [**TwigBundle**][8] - Adds support for the Twig templating engine - - * [**SecurityBundle**][9] - Adds security by integrating Symfony's security - component - - * [**SwiftmailerBundle**][10] - Adds support for Swiftmailer, a library for - sending emails - - * [**MonologBundle**][11] - Adds support for Monolog, a logging library - - * [**AsseticBundle**][12] - Adds support for Assetic, an asset processing - library - - * **WebProfilerBundle** (in dev/test env) - Adds profiling functionality and - the web debug toolbar - - * **SensioDistributionBundle** (in dev/test env) - Adds functionality for - configuring and working with Symfony distributions - - * [**SensioGeneratorBundle**][13] (in dev/test env) - Adds code generation - capabilities - -All libraries and bundles included in the Symfony Standard Edition are -released under the MIT or BSD license. - -Enjoy! - -[1]: http://symfony.com/doc/2.7/book/installation.html -[6]: http://symfony.com/doc/2.7/bundles/SensioFrameworkExtraBundle/index.html -[7]: http://symfony.com/doc/2.7/book/doctrine.html -[8]: http://symfony.com/doc/2.7/book/templating.html -[9]: http://symfony.com/doc/2.7/book/security.html -[10]: http://symfony.com/doc/2.7/cookbook/email.html -[11]: http://symfony.com/doc/2.7/cookbook/logging/monolog.html -[12]: http://symfony.com/doc/2.7/cookbook/assetic/asset_management.html -[13]: http://symfony.com/doc/2.7/bundles/SensioGeneratorBundle/index.html +```shell +php app/console assetic:dump +``` \ No newline at end of file diff --git a/app/AppKernel.php b/app/AppKernel.php index 9be1531..bb83ba1 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -19,6 +19,7 @@ class AppKernel extends Kernel new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new DT\Bundle\GeshiBundle\DTGeshiBundle(), + new Braincrafted\Bundle\BootstrapBundle\BraincraftedBootstrapBundle(), new Skobkin\Bundle\CopyPasteBundle\SkobkinCopyPasteBundle(), ); diff --git a/app/DoctrineMigrations/Version20150303224825.php b/app/DoctrineMigrations/Version20150303224825.php new file mode 100644 index 0000000..4460679 --- /dev/null +++ b/app/DoctrineMigrations/Version20150303224825.php @@ -0,0 +1,22 @@ +addSql('UPDATE copypastes SET secret=NULL WHERE secret=\'\''); + } + + public function down(Schema $schema) + { + $this->addSql('UPDATE copypastes SET secret=\'\' WHERE secret=NULL'); + } +} diff --git a/app/DoctrineMigrations/Version20150305184842.php b/app/DoctrineMigrations/Version20150305184842.php new file mode 100644 index 0000000..4eac22a --- /dev/null +++ b/app/DoctrineMigrations/Version20150305184842.php @@ -0,0 +1,23 @@ +addSql('UPDATE copypastes SET date_expire=NULL WHERE date_expire=\'0000-00-00 00:00:00\''); + + } + + public function down(Schema $schema) + { + $this->addSql('UPDATE copypastes SET date_expire=\'0000-00-00 00:00:00\' WHERE date_expire=NULL'); + } +} diff --git a/app/DoctrineMigrations/Version20150316014139.php b/app/DoctrineMigrations/Version20150316014139.php new file mode 100644 index 0000000..d28ba5c --- /dev/null +++ b/app/DoctrineMigrations/Version20150316014139.php @@ -0,0 +1,32 @@ + is_enabled + * - is_preferred added + */ +class Version20150316014139 extends AbstractMigration +{ + public function up(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE languages CHANGE enabled is_enabled TINYINT(1) NOT NULL'); + $this->addSql('ALTER TABLE languages ADD is_preferred TINYINT(1) NOT NULL'); + $this->addSql('CREATE INDEX idx_preferred ON languages (is_preferred)'); + } + + public function down(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE languages CHANGE is_enabled enabled TINYINT(1) NOT NULL'); + $this->addSql('ALTER TABLE languages DROP is_preferred'); + $this->addSql('DROP INDEX idx_preferred ON languages'); + } +} diff --git a/app/Resources/translations/messages.ru.xliff b/app/Resources/translations/messages.ru.xliff new file mode 100644 index 0000000..576199b --- /dev/null +++ b/app/Resources/translations/messages.ru.xliff @@ -0,0 +1,119 @@ + + + + + + header_title + CopyPaste + + + sidebar_title + Последние + + + header_menu_add + Добавить + + + header_menu_about + О сервисе + + + header_menu_api + API + + + paste_add_form_text + Текст + + + paste_add_form_description + Описание + + + paste_add_form_file_name + Имя файла + + + paste_add_form_author + Автор + + + paste_add_form_expire + Удалить через + + + paste_add_form_private + Секретно + + + paste_add_form_language + Язык + + + Create + Создать + + + paste_view_tab_view + Просмотр + + + paste_view_tab_edit + Правка + + + paste_show_qr_show + Показать QR + + + paste_show_download + Скачать + + + 5 minutes + 5 минут + + + 1 hour + 1 час + + + 3 hours + 3 часа + + + 12 hours + 12 часов + + + 1 day + 1 день + + + 1 week + 1 неделя + + + 1 month + 1 месяц + + + 3 months + 3 месяца + + + 6 months + 6 месяцев + + + 1 year + 1 год + + + Never + Никогда + + + + \ No newline at end of file diff --git a/app/Resources/views/base.html.twig b/app/Resources/views/base.html.twig index bafd28d..54bb649 100644 --- a/app/Resources/views/base.html.twig +++ b/app/Resources/views/base.html.twig @@ -1,13 +1,52 @@ - - - - - {% block title %}Welcome!{% endblock %} - {% block stylesheets %}{% endblock %} - - - - {% block body %}{% endblock %} - {% block javascripts %}{% endblock %} - - +{% extends '::layout.html.twig' -%} + +{%- block css -%} + {{- parent() -}} + +{% endblock %} +{% block javascript %} + {{- parent() -}} + +{% endblock %} + +{%- block header -%} + +{%- endblock -%} + +{%- block sidebar -%} + {{ render(controller('SkobkinCopyPasteBundle:CopyPaste:sidebar')) }} +{%- endblock -%} + +{% block content %}{% endblock %} diff --git a/app/Resources/views/layout.html.twig b/app/Resources/views/layout.html.twig new file mode 100644 index 0000000..8bbbd95 --- /dev/null +++ b/app/Resources/views/layout.html.twig @@ -0,0 +1,45 @@ + + + + {%- block head -%} + {% block title %}CopyPaste{% endblock %} + + + {%- block css -%} + + {%- endblock -%} + {# HTML5 Shim and Respond.js add IE8 support of HTML5 elements and media queries #} + {% include 'BraincraftedBootstrapBundle::ie8-support.html.twig' %} + {%- endblock -%} + + + {% block body %} +
+ {% block containter %} +
+ {% block header %}{% endblock %} +
+ +
+
+ {% block sidebar %}{% endblock %} +
+
+ {% block content %}{% endblock %} +
+
+ +
+ {% block footer %}{% endblock %} +
+ {% endblock %} +
+ + {% block javascript %} + + {# Include all JavaScripts, compiled by Assetic #} + + {% endblock %} + {% endblock %} + + \ No newline at end of file diff --git a/app/Resources/views/sidebar.html.twig b/app/Resources/views/sidebar.html.twig new file mode 100644 index 0000000..9be9cee --- /dev/null +++ b/app/Resources/views/sidebar.html.twig @@ -0,0 +1,12 @@ +
+
+
{{ 'sidebar_title' | trans() }}
+ +
+
diff --git a/app/config/config.yml b/app/config/config.yml index b916725..804aaaa 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -5,7 +5,7 @@ imports: framework: #esi: ~ - #translator: { fallbacks: ["%locale%"] } + translator: { fallbacks: ["%locale%"] } secret: "%secret%" router: resource: "%kernel.root_dir%/config/routing.yml" @@ -37,12 +37,32 @@ assetic: bundles: [ ] #java: /usr/bin/java filters: + less: + node: "%nodejs_executable%" + node_paths: %nodejs_paths% + apply_to: "\.less$" cssrewrite: ~ #closure: # jar: "%kernel.root_dir%/Resources/java/compiler.jar" #yui_css: # jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar" +braincrafted_bootstrap: + output_dir: bootstrap + assets_dir: %kernel.root_dir%/../vendor/twbs/bootstrap + jquery_path: %kernel.root_dir%/../vendor/components/jquery/jquery.js + less_filter: less + fonts_dir: %kernel.root_dir%/../web/bootstrap/fonts + auto_configure: + assetic: true + twig: true + knp_menu: true + knp_paginator: true + customize: + variables_file: ~ + bootstrap_output: %kernel.root_dir%/Resources/less/bootstrap.less + bootstrap_template: BraincraftedBootstrapBundle:Bootstrap:bootstrap.less.twig + # Doctrine Configuration doctrine: dbal: diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 1da778f..497b294 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -18,3 +18,8 @@ parameters: # A secret key that's used to generate certain security-related tokens secret: ThisTokenIsNotSoSecretChangeIt + + # Other stuff + nodejs_executable: /usr/bin/node + nodejs_paths: [/usr/lib/node_modules/] + \ No newline at end of file diff --git a/composer.json b/composer.json index f675302..474c990 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,10 @@ "doctrine/doctrine-migrations-bundle": "2.1.*@dev", "doctrine/doctrine-fixtures-bundle": "2.2.*", "theodordiaconu/geshi": "dev-master", - "theodordiaconu/geshi-bundle" : "dev-master" + "theodordiaconu/geshi-bundle" : "dev-master", + "braincrafted/bootstrap-bundle": "dev-master", + "twbs/bootstrap": "3.3.*@dev", + "components/jquery": "dev-master" }, "require-dev": { "sensio/generator-bundle": "~2.3" diff --git a/composer.lock b/composer.lock index 071deca..b263cff 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,110 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "e36598c346f19a7d683f1c1f3d58399f", + "hash": "06492598a20c478faba66c1691e8490c", "packages": [ + { + "name": "braincrafted/bootstrap-bundle", + "version": "dev-master", + "target-dir": "Braincrafted/Bundle/BootstrapBundle", + "source": { + "type": "git", + "url": "https://github.com/braincrafted/bootstrap-bundle.git", + "reference": "2dc17466f95a035869b51c845024f6a92bc1d6d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/braincrafted/bootstrap-bundle/zipball/2dc17466f95a035869b51c845024f6a92bc1d6d1", + "reference": "2dc17466f95a035869b51c845024f6a92bc1d6d1", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/console": "~2.3", + "symfony/finder": "~2.3", + "symfony/form": "~2.3", + "symfony/framework-bundle": "~2.3", + "symfony/twig-bundle": "~2.3" + }, + "require-dev": { + "knplabs/knp-menu": "~2.0@alpha", + "knplabs/knp-menu-bundle": "~2.0@alpha", + "knplabs/knp-paginator-bundle": "dev-master", + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "3.7.*", + "symfony/assetic-bundle": "~2.3" + }, + "suggest": { + "knplabs/knp-menu": "Required to use KnpMenuBundle.", + "knplabs/knp-menu-bundle": "BraincraftedBootstrapBundle styles the menus provided by KnpMenuBundle.", + "knplabs/knp-paginator-bundle": "BraincraftedBootstrapBundle styles the pagination provided by KnpPaginatorBundle.", + "twbs/bootstrap": "Twitter Bootstrap provides the assets (images, CSS and JS)" + }, + "type": "symfony-bundle", + "autoload": { + "psr-0": { + "Braincrafted\\Bundle\\BootstrapBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florian Eckerstorfer", + "email": "florian@eckerstorfer.co", + "homepage": "http://florian.ec" + } + ], + "description": "BraincraftedBootstrapBundle integrates Bootstrap into Symfony2 by providing templates, Twig extensions, services and commands.", + "keywords": [ + "bootstrap" + ], + "time": "2015-01-31 10:32:31" + }, + { + "name": "components/jquery", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/components/jquery.git", + "reference": "f8edb647d1833fd5d57410ab70860f03534cb2e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/components/jquery/zipball/f8edb647d1833fd5d57410ab70860f03534cb2e8", + "reference": "f8edb647d1833fd5d57410ab70860f03534cb2e8", + "shasum": "" + }, + "type": "component", + "extra": { + "component": { + "scripts": [ + "jquery.js" + ], + "files": [ + "jquery.min.js", + "jquery.min.map", + "jquery-migrate.js", + "jquery-migrate.min.js" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Resig", + "email": "jeresig@gmail.com" + } + ], + "description": "jQuery JavaScript Library", + "homepage": "http://jquery.com", + "time": "2014-12-23 06:48:45" + }, { "name": "doctrine/annotations", "version": "v1.2.3", @@ -816,12 +918,12 @@ "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "058a4635ac9b80a5b1997df28a754e64b1425a1d" + "reference": "312fb5939d5b9dbd66e515374533933e7c5cc8a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/058a4635ac9b80a5b1997df28a754e64b1425a1d", - "reference": "058a4635ac9b80a5b1997df28a754e64b1425a1d", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/312fb5939d5b9dbd66e515374533933e7c5cc8a6", + "reference": "312fb5939d5b9dbd66e515374533933e7c5cc8a6", "shasum": "" }, "require": { @@ -866,7 +968,7 @@ "database", "migrations" ], - "time": "2015-02-19 08:13:05" + "time": "2015-03-02 18:28:52" }, { "name": "doctrine/orm", @@ -1626,12 +1728,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/symfony.git", - "reference": "755ea09a440c1b8ea560e403b442fc9f53e0ae93" + "reference": "12cf04f8f341573a146cdc32722f72ae2deb0579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/symfony/zipball/755ea09a440c1b8ea560e403b442fc9f53e0ae93", - "reference": "755ea09a440c1b8ea560e403b442fc9f53e0ae93", + "url": "https://api.github.com/repos/symfony/symfony/zipball/12cf04f8f341573a146cdc32722f72ae2deb0579", + "reference": "12cf04f8f341573a146cdc32722f72ae2deb0579", "shasum": "" }, "require": { @@ -1735,7 +1837,7 @@ "keywords": [ "framework" ], - "time": "2015-03-02 10:21:01" + "time": "2015-03-03 08:32:45" }, { "name": "theodordiaconu/geshi", @@ -1817,6 +1919,57 @@ ], "time": "2013-03-29 12:54:06" }, + { + "name": "twbs/bootstrap", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/twbs/bootstrap.git", + "reference": "ddd09f6fe773c4a99929c169b80882ed955a6227" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/ddd09f6fe773c4a99929c169b80882ed955a6227", + "reference": "ddd09f6fe773c4a99929c169b80882ed955a6227", + "shasum": "" + }, + "replace": { + "twitter/bootstrap": "self.version" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jacob Thornton", + "email": "jacobthornton@gmail.com" + }, + { + "name": "Mark Otto", + "email": "markdotto@gmail.com" + } + ], + "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", + "homepage": "http://getbootstrap.com", + "keywords": [ + "JS", + "css", + "framework", + "front-end", + "less", + "mobile-first", + "responsive", + "web" + ], + "time": "2015-03-03 06:03:42" + }, { "name": "twig/extensions", "version": "v1.2.0", @@ -1984,7 +2137,10 @@ "doctrine/migrations": 20, "doctrine/doctrine-migrations-bundle": 20, "theodordiaconu/geshi": 20, - "theodordiaconu/geshi-bundle": 20 + "theodordiaconu/geshi-bundle": 20, + "braincrafted/bootstrap-bundle": 20, + "twbs/bootstrap": 20, + "components/jquery": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Controller/CopypasteController.php b/src/Skobkin/Bundle/CopyPasteBundle/Controller/CopypasteController.php new file mode 100644 index 0000000..c815ffd --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Controller/CopypasteController.php @@ -0,0 +1,154 @@ +createCreateForm($paste); + $form->handleRequest($request); + + if ($form->isValid()) { + $em = $this->getDoctrine()->getManager(); + + if ($form->get('private')->getData()) { + // Private paste + $paste->setSecret(substr(md5($paste->getText()), 0, 16)); + } + + $expire = (int) $form->get('expire')->getData(); + //var_dump($expire); exit(); + if ($expire) { + $dateExpire = new \DateTime(); + $dateExpire->add(new \DateInterval('PT' . $expire . 'S')); + $paste->setDateExpire($dateExpire); + } + + $paste->setIp($request->getClientIp()); + + $em->persist($paste); + $em->flush(); + + if ($paste->isPrivate()) { + return $this->redirect($this->generateUrl('copypaste_show_private', ['id' => $paste->getId(), 'secret' => $paste->getSecret()])); + } else { + return $this->redirect($this->generateUrl('copypaste_show_public', ['id' => $paste->getId()])); + } + } + + throw new $this->createAccessDeniedException('Sorry :('); + } + + /** + * Creates a form to create a Copypaste entity. + * + * @param Copypaste $entity The entity + * + * @return Form The form + */ + private function createCreateForm(Copypaste $entity) + { + $form = $this->createForm(new CopypasteType(), $entity, [ + 'action' => $this->generateUrl('copypaste_create'), + 'method' => 'POST', + ]); + + $form->add('submit', 'submit', array('label' => 'Create')); + + return $form; + } + + /** + * Displays a form to create a new Copypaste entity. + * + * @return Response + */ + public function newAction() + { + $paste = new Copypaste(); + $createForm = $this->createCreateForm($paste); + + return $this->render('SkobkinCopyPasteBundle:Copypaste:new.html.twig', [ + 'entity' => $paste, + 'form_create' => $createForm->createView(), + ]); + } + + /** + * Finds and displays a Copypaste entity. + * + * @return Response + */ + public function showAction($id, $secret) + { + $em = $this->getDoctrine()->getManager(); + + /* @var $paste Copypaste */ + $paste = $em->getRepository('SkobkinCopyPasteBundle:Copypaste')->findOneBy([ + 'id' =>$id, + 'secret' => $secret + ]); + + if (!$paste) { + throw $this->createNotFoundException('Unable to find copypaste.'); + } + + $editForm = $this->createCreateForm($paste); + + /* @var $highlighter GeshiHighlighter */ + $highlighter = $this->get('dt_geshi.highlighter'); + + $highlightedCode = $highlighter->highlight($paste->getText(), $paste->getLanguage()->getCode(), function(GeSHi $geshi) { + $geshi->set_header_type(GESHI_HEADER_PRE); + $geshi->enable_line_numbers(GESHI_NO_LINE_NUMBERS); + }); + + return $this->render('SkobkinCopyPasteBundle:Copypaste:show.html.twig', [ + 'paste' => $paste, + 'highlighted_text' => $highlightedCode, + 'form_create' => $editForm->createView(), + ]); + } + + /** + * Main page + * + * @return Response + */ + public function sidebarAction() + { + $em = $this->getDoctrine()->getManager(); + + $pastes = $em->getRepository('SkobkinCopyPasteBundle:Copypaste')->findBy( + ['secret' => null], + ['id' => 'DESC'], + // @todo move to the config + 15 + ); + + return $this->render('::sidebar.html.twig', ['pastes' => $pastes]); + } + + +} diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Entity/Copypaste.php b/src/Skobkin/Bundle/CopyPasteBundle/Entity/Copypaste.php index ed58077..071be71 100644 --- a/src/Skobkin/Bundle/CopyPasteBundle/Entity/Copypaste.php +++ b/src/Skobkin/Bundle/CopyPasteBundle/Entity/Copypaste.php @@ -3,17 +3,16 @@ namespace Skobkin\Bundle\CopyPasteBundle\Entity; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; /** * Copypaste * - * @ORM\Table( - * name="copypastes", - * indexes={ - * @ORM\Index(name="idx_expire", columns={"date_expire"}) - * } - * ) + * @ORM\Table(name="copypastes", indexes={ + * @ORM\Index(name="idx_expire", columns={"date_expire"}) + * }) * @ORM\Entity + * @ORM\HasLifecycleCallbacks() */ class Copypaste { @@ -38,7 +37,7 @@ class Copypaste * * @ORM\Column(name="description", type="text", nullable=true) */ - private $description; + private $description = null; /** * @var Language @@ -53,14 +52,14 @@ class Copypaste * * @ORM\Column(name="file_name", type="string", length=128, nullable=true) */ - private $fileName; + private $fileName = null; /** * @var string * * @ORM\Column(name="author", type="string", length=48, nullable=true) */ - private $author; + private $author = null; /** * @var \DateTime @@ -74,11 +73,12 @@ class Copypaste * * @ORM\Column(name="date_expire", type="datetime", nullable=true) */ - private $dateExpire; + private $dateExpire = null; /** * @var string * + * @Assert\Ip * @ORM\Column(name="ip", type="string", length=48, nullable=false) */ private $ip; @@ -88,9 +88,15 @@ class Copypaste * * @ORM\Column(name="secret", type="string", length=16, nullable=true) */ - private $secret; - + private $secret = null; + /** + * @ORM\PrePersist + */ + public function prePersist() + { + $this->datePublished = new \DateTime(); + } /** * Get id @@ -101,6 +107,11 @@ class Copypaste { return $this->id; } + + public function __toString() + { + return $this->id; + } /** * Set text diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Entity/Language.php b/src/Skobkin/Bundle/CopyPasteBundle/Entity/Language.php index 8ef60a1..8eaa8b0 100644 --- a/src/Skobkin/Bundle/CopyPasteBundle/Entity/Language.php +++ b/src/Skobkin/Bundle/CopyPasteBundle/Entity/Language.php @@ -7,13 +7,11 @@ use Doctrine\ORM\Mapping as ORM; /** * Language * - * @ORM\Table( - * name="languages", - * indexes={ - * @ORM\Index(name="idx_enabled", columns={"enabled"}), - * @ORM\Index(name="idx_code", columns={"code"}) - * } - * ) + * @ORM\Table(name="languages", indexes={ + * @ORM\Index(name="idx_enabled", columns={"is_enabled"}), + * @ORM\Index(name="idx_preferred", columns={"is_preferred"}), + * @ORM\Index(name="idx_code", columns={"code"}) + * }) * @ORM\Entity */ class Language @@ -40,13 +38,20 @@ class Language * @ORM\Column(name="code", type="string", length=24, nullable=false) */ private $code; + + /** + * @var boolean + * + * @ORM\Column(name="is_preferred", type="boolean", nullable=false) + */ + private $isPreferred = false; /** * @var boolean * - * @ORM\Column(name="enabled", type="boolean", nullable=false) + * @ORM\Column(name="is_enabled", type="boolean", nullable=false) */ - private $enabled; + private $isEnabled; @@ -59,6 +64,11 @@ class Language { return $this->id; } + + public function __toString() + { + return $this->name; + } /** * Set name @@ -86,7 +96,7 @@ class Language /** * Set code * - * @param string $file + * @param string $code * @return Lang */ public function setCode($code) @@ -107,35 +117,47 @@ class Language } /** - * Set enabled + * Set isEnabled * - * @param boolean $enabled + * @param boolean $isEnabled * @return Lang */ - public function setEnabled($enabled) + public function setIsEnabled($isEnabled) { - $this->enabled = $enabled; + $this->isEnabled = $isEnabled; return $this; } /** - * Get enabled + * Get isEnabled * * @return boolean */ - public function getEnabled() + public function getIsEnabled() { - return $this->enabled; + return $this->isEnabled; } /** - * Check if language is enabled + * Get isPreferred * * @return boolean */ - public function isEnabled() + function getIsPreferred() { - return $this->enabled; + return $this->isPreferred; + } + + /** + * Set isPreferred + * + * @param boolean $isPreferred + */ + function setIsPreferred($isPreferred) + { + $this->isPreferred = $isPreferred; + + return $this; } } diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Form/CopypasteType.php b/src/Skobkin/Bundle/CopyPasteBundle/Form/CopypasteType.php new file mode 100644 index 0000000..c1d69a4 --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Form/CopypasteType.php @@ -0,0 +1,90 @@ +add('text', 'textarea', ['label' => 'paste_add_form_text']) + ->add('description', 'textarea', [ + 'label' => 'paste_add_form_description', + 'required' => false, + ]) + ->add('fileName', 'text', [ + 'label' => 'paste_add_form_file_name', + 'required' => false, + ]) + ->add('author', 'text', [ + 'label' => 'paste_add_form_author', + 'required' => false, + ]) + ->add('expire', 'choice', [ + 'label' => 'paste_add_form_expire', + 'mapped' => false, + // @todo move to config + 'choices' => [ + 300 => '5 minutes', + 3600 => '1 hour', + 10800 => '3 hours', + 43200 => '12 hours', + 86400 => '1 day', + 604800 => '1 week', + 2419200 => '1 month', + 7257600 => '3 months', + 14515200 => '6 months', + 29030400 => '1 year', + 0 => 'Never', + ] + ]) + ->add('private', 'checkbox', [ + 'label' => 'paste_add_form_private', + 'required' => false, + 'mapped' => false + ]) + ->add('language', 'entity', [ + 'label' => 'paste_add_form_language', + 'class' => 'Skobkin\Bundle\CopyPasteBundle\Entity\Language', + 'query_builder' => function (EntityRepository $repo) { + /* @var $qb QueryBuilder */ + return $repo->createQueryBuilder('lang') + ->where('lang.isEnabled = :enabled') + ->addOrderBy('lang.isPreferred', 'DESC') + ->addOrderBy('lang.code') + ->setParameter('enabled', true); + }, + //'preferred_choices' => [] + ]) + ->add('actions', 'form_actions') + ; + } + + /** + * @param OptionsResolverInterface $resolver + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Skobkin\Bundle\CopyPasteBundle\Entity\Copypaste' + ]); + } + + /** + * @return string + */ + public function getName() + { + return 'skobkin_bundle_copypastebundle_copypaste'; + } +} diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing.yml b/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing.yml index 8b13789..8e4a1d7 100644 --- a/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing.yml +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing.yml @@ -1 +1,3 @@ - +skobkin_copy_paste: + resource: "@SkobkinCopyPasteBundle/Resources/config/routing/copypaste.yml" + prefix: / diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing/copypaste.yml b/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing/copypaste.yml new file mode 100644 index 0000000..45938d3 --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/config/routing/copypaste.yml @@ -0,0 +1,21 @@ +copypaste_show_public: + path: /{id} + defaults: { _controller: "SkobkinCopyPasteBundle:Copypaste:show", secret: null } + requirements: + id: \d+ + +copypaste_show_private: + path: /{id}/{secret} + defaults: { _controller: "SkobkinCopyPasteBundle:Copypaste:show" } + requirements: + id: \d+ + secret: \w{16} + +copypaste_new: + path: / + defaults: { _controller: "SkobkinCopyPasteBundle:Copypaste:new" } + +copypaste_create: + path: /create + defaults: { _controller: "SkobkinCopyPasteBundle:Copypaste:create" } + methods: POST \ No newline at end of file diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/css/base.css b/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/css/base.css new file mode 100644 index 0000000..bdfb38b --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/css/base.css @@ -0,0 +1,44 @@ +/* + Created on : Mar 3, 2015, 6:53:42 PM + Author : Alexey Skobkin +*/ + +html { + position: relative; + min-height: 100%; +} + +body { + /* Margin bottom by footer height */ + margin-bottom: 60px; + padding-top: 70px; +} + +.navbar-brand { + font-weight: bold; +} + +/* @todo Fix crutches and bycicles */ +.editor-head button[type="submit"] { + margin-top: 24px; +} + +.editor-description { + margin-top: 10px; +} + +.editor-head .form-group, .editor-head .checkbox { + margin-bottom: 0; +} + +.paste-main #tab-paste-edit, .paste-main #tab-paste-view { + padding-top: 10px; +} + +.paste-description-content { + margin-top: 10px; +} + +.paste-main .paste-tabs { + margin-top: 10px; +} \ No newline at end of file diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/images/favicon.ico b/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/images/favicon.ico new file mode 100644 index 0000000..e59f188 Binary files /dev/null and b/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/images/favicon.ico differ diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/js/copypaste.js b/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/js/copypaste.js new file mode 100644 index 0000000..977dfde --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/public/js/copypaste.js @@ -0,0 +1,9 @@ +$(function () { + var $qr_link = $('#paste-qr-code'); + $qr_link.popover({ + content: '', + placement: 'bottom', + trigger: 'focus', + html: true + }); +}); \ No newline at end of file diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Copypaste/new.html.twig b/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Copypaste/new.html.twig new file mode 100644 index 0000000..69f87c5 --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Copypaste/new.html.twig @@ -0,0 +1,6 @@ +{% extends '::base.html.twig' %} + +{% block content %} + {# This form recieves form_create object from current context #} + {% include 'SkobkinCopyPasteBundle:Form:form_paste_create.html.twig' %} +{% endblock %} diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Copypaste/show.html.twig b/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Copypaste/show.html.twig new file mode 100644 index 0000000..dff9048 --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Copypaste/show.html.twig @@ -0,0 +1,76 @@ +{% extends '::base.html.twig' %} + +{% block content %} +
+
+
+ {% if paste.author %} + {{ paste.author }} + {% else %} + anonymous + {% endif %} +
+
{{ paste.language }}
+
{{ paste.datePublished | date('Y.m.d H:i') }}
+
+ {% if paste.dateExpire %} + {{ paste.dateExpire | date('Y.m.d H:i') }} + {% endif %} +
+ + +
+ {% if paste.description %} +
+
+
+ {{ paste.description | nl2br }} +
+
+
+ {% endif %} +
+
+
+ + + + +
+
+
+ {{ highlighted_text | raw }} +
+
+
+ {# This form recieves form_create object from current context #} + {% include 'SkobkinCopyPasteBundle:Form:form_paste_create.html.twig' %} +
+
+
+
+
+
+{% endblock %} diff --git a/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Form/form_paste_create.html.twig b/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Form/form_paste_create.html.twig new file mode 100644 index 0000000..25fc7c2 --- /dev/null +++ b/src/Skobkin/Bundle/CopyPasteBundle/Resources/views/Form/form_paste_create.html.twig @@ -0,0 +1,42 @@ +
+ {{ form_start(form_create) }} +
+
+
+ {{ form_row(form_create.author) }} +
+
+ {{ form_row(form_create.language) }} +
+
+ {{ form_row(form_create.expire) }} + {{ form_row(form_create.private) }} +
+
+
+ {{ form_widget(form_create.submit) }} +
+
+
+
+
+ {{ form_label(form_create.text) }} + {{ form_errors(form_create.text) }} + {{ form_widget(form_create.text, {'attr': {'rows': 10}}) }} +
+
+
+
+ {{ form_row(form_create.fileName) }} +
+
+
+
+ {{ form_label(form_create.description) }} + {{ form_errors(form_create.description) }} + {{ form_widget(form_create.description) }} +
+
+
+ {{ form_end(form_create) }} +
\ No newline at end of file diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png deleted file mode 100644 index 11f17e6..0000000 Binary files a/web/apple-touch-icon.png and /dev/null differ