Repository: thecodeholic/Yii2-Youtube-Clone Branch: master Commit: d8d6c35890b5 Files: 237 Total size: 254.7 KB Directory structure: gitextract_etck1_vw/ ├── .bowerrc ├── .gitignore ├── LICENSE.md ├── README.md ├── Vagrantfile ├── backend/ │ ├── Dockerfile │ ├── assets/ │ │ ├── AppAsset.php │ │ └── TagsInputAsset.php │ ├── codeception.yml │ ├── config/ │ │ ├── .gitignore │ │ ├── bootstrap.php │ │ ├── main.php │ │ ├── params.php │ │ └── test.php │ ├── controllers/ │ │ ├── CommentController.php │ │ ├── SiteController.php │ │ └── VideoController.php │ ├── models/ │ │ ├── .gitkeep │ │ └── CommentSearch.php │ ├── runtime/ │ │ └── .gitignore │ ├── tests/ │ │ ├── _bootstrap.php │ │ ├── _data/ │ │ │ ├── .gitignore │ │ │ └── login_data.php │ │ ├── _output/ │ │ │ └── .gitignore │ │ ├── _support/ │ │ │ ├── .gitignore │ │ │ ├── FunctionalTester.php │ │ │ └── UnitTester.php │ │ ├── functional/ │ │ │ ├── LoginCest.php │ │ │ └── _bootstrap.php │ │ ├── functional.suite.yml │ │ ├── unit/ │ │ │ └── _bootstrap.php │ │ └── unit.suite.yml │ ├── views/ │ │ ├── comment/ │ │ │ ├── _comment_item.php │ │ │ ├── _form.php │ │ │ ├── _item.php │ │ │ ├── _search.php │ │ │ ├── create.php │ │ │ ├── index.php │ │ │ ├── update.php │ │ │ └── view.php │ │ ├── layouts/ │ │ │ ├── _header.php │ │ │ ├── _sidebar.php │ │ │ ├── auth.php │ │ │ ├── base.php │ │ │ └── main.php │ │ ├── site/ │ │ │ ├── error.php │ │ │ ├── index.php │ │ │ └── login.php │ │ └── video/ │ │ ├── _form.php │ │ ├── _video_item.php │ │ ├── create.php │ │ ├── index.php │ │ └── update.php │ └── web/ │ ├── app.js │ ├── assets/ │ │ └── .gitignore │ ├── css/ │ │ └── site.css │ └── tagsinput/ │ ├── tagsinput.css │ └── tagsinput.js ├── codeception.yml ├── common/ │ ├── codeception.yml │ ├── config/ │ │ ├── .gitignore │ │ ├── bootstrap.php │ │ ├── main.php │ │ ├── params.php │ │ └── test.php │ ├── fixtures/ │ │ └── UserFixture.php │ ├── helpers/ │ │ └── Html.php │ ├── mail/ │ │ ├── emailVerify-html.php │ │ ├── emailVerify-text.php │ │ ├── layouts/ │ │ │ ├── html.php │ │ │ └── text.php │ │ ├── mention-html.php │ │ ├── mention-text.php │ │ ├── passwordResetToken-html.php │ │ ├── passwordResetToken-text.php │ │ ├── subscriber-html.php │ │ └── subscriber-text.php │ ├── models/ │ │ ├── Comment.php │ │ ├── LoginForm.php │ │ ├── Subscriber.php │ │ ├── User.php │ │ ├── Video.php │ │ ├── VideoLike.php │ │ ├── VideoView.php │ │ └── query/ │ │ ├── CommentQuery.php │ │ ├── SubscriberQuery.php │ │ ├── VideoLikeQuery.php │ │ ├── VideoQuery.php │ │ └── VideoViewQuery.php │ ├── tests/ │ │ ├── _bootstrap.php │ │ ├── _data/ │ │ │ └── user.php │ │ ├── _output/ │ │ │ └── .gitignore │ │ ├── _support/ │ │ │ ├── .gitignore │ │ │ └── UnitTester.php │ │ ├── unit/ │ │ │ └── models/ │ │ │ └── LoginFormTest.php │ │ └── unit.suite.yml │ └── widgets/ │ └── Alert.php ├── composer.json ├── console/ │ ├── config/ │ │ ├── .gitignore │ │ ├── bootstrap.php │ │ ├── main.php │ │ ├── params.php │ │ └── test.php │ ├── controllers/ │ │ └── .gitkeep │ ├── migrations/ │ │ ├── m130524_201442_init.php │ │ ├── m190124_110200_add_verification_token_column_to_user_table.php │ │ ├── m200417_054237_create_videos_table.php │ │ ├── m200418_050048_create_video_view_table.php │ │ ├── m200418_051244_create_video_like_table.php │ │ ├── m200418_060320_create_subscriber_table.php │ │ ├── m200418_064142_create_fulltext_index_on_video.php │ │ ├── m201112_042619_create_comment_table.php │ │ └── m201115_124738_add_mention_column_to_comment_table.php │ ├── models/ │ │ └── .gitkeep │ └── runtime/ │ └── .gitignore ├── docker-compose.yml ├── environments/ │ ├── dev/ │ │ ├── backend/ │ │ │ ├── config/ │ │ │ │ ├── codeception-local.php │ │ │ │ ├── main-local.php │ │ │ │ ├── params-local.php │ │ │ │ └── test-local.php │ │ │ └── web/ │ │ │ ├── index-test.php │ │ │ ├── index.php │ │ │ └── robots.txt │ │ ├── common/ │ │ │ └── config/ │ │ │ ├── codeception-local.php │ │ │ ├── main-local.php │ │ │ ├── params-local.php │ │ │ └── test-local.php │ │ ├── console/ │ │ │ └── config/ │ │ │ ├── main-local.php │ │ │ ├── params-local.php │ │ │ └── test-local.php │ │ ├── frontend/ │ │ │ ├── config/ │ │ │ │ ├── codeception-local.php │ │ │ │ ├── main-local.php │ │ │ │ ├── params-local.php │ │ │ │ └── test-local.php │ │ │ └── web/ │ │ │ ├── index-test.php │ │ │ ├── index.php │ │ │ └── robots.txt │ │ ├── yii │ │ ├── yii_test │ │ └── yii_test.bat │ ├── index.php │ └── prod/ │ ├── backend/ │ │ ├── config/ │ │ │ ├── main-local.php │ │ │ └── params-local.php │ │ └── web/ │ │ ├── index.php │ │ └── robots.txt │ ├── common/ │ │ └── config/ │ │ ├── main-local.php │ │ └── params-local.php │ ├── console/ │ │ └── config/ │ │ ├── main-local.php │ │ └── params-local.php │ ├── frontend/ │ │ ├── config/ │ │ │ ├── main-local.php │ │ │ └── params-local.php │ │ └── web/ │ │ ├── index.php │ │ └── robots.txt │ └── yii ├── frontend/ │ ├── Dockerfile │ ├── assets/ │ │ └── AppAsset.php │ ├── codeception.yml │ ├── config/ │ │ ├── .gitignore │ │ ├── bootstrap.php │ │ ├── main.php │ │ ├── params.php │ │ └── test.php │ ├── controllers/ │ │ ├── ChannelController.php │ │ ├── CommentController.php │ │ ├── SiteController.php │ │ └── VideoController.php │ ├── models/ │ │ ├── PasswordResetRequestForm.php │ │ ├── ResendVerificationEmailForm.php │ │ ├── ResetPasswordForm.php │ │ ├── SignupForm.php │ │ └── VerifyEmailForm.php │ ├── runtime/ │ │ └── .gitignore │ ├── tests/ │ │ ├── _bootstrap.php │ │ ├── _data/ │ │ │ ├── login_data.php │ │ │ └── user.php │ │ ├── _output/ │ │ │ └── .gitignore │ │ ├── _support/ │ │ │ ├── .gitignore │ │ │ ├── FunctionalTester.php │ │ │ └── UnitTester.php │ │ ├── acceptance/ │ │ │ ├── HomeCest.php │ │ │ └── _bootstrap.php │ │ ├── acceptance.suite.yml.example │ │ ├── functional/ │ │ │ ├── AboutCest.php │ │ │ ├── ContactCest.php │ │ │ ├── HomeCest.php │ │ │ ├── LoginCest.php │ │ │ ├── ResendVerificationEmailCest.php │ │ │ ├── SignupCest.php │ │ │ ├── VerifyEmailCest.php │ │ │ └── _bootstrap.php │ │ ├── functional.suite.yml │ │ ├── unit/ │ │ │ ├── _bootstrap.php │ │ │ └── models/ │ │ │ ├── ContactFormTest.php │ │ │ ├── PasswordResetRequestFormTest.php │ │ │ ├── ResendVerificationEmailFormTest.php │ │ │ ├── ResetPasswordFormTest.php │ │ │ ├── SignupFormTest.php │ │ │ └── VerifyEmailFormTest.php │ │ └── unit.suite.yml │ ├── views/ │ │ ├── channel/ │ │ │ ├── _subscribe.php │ │ │ └── view.php │ │ ├── layouts/ │ │ │ ├── _header.php │ │ │ ├── _sidebar.php │ │ │ ├── auth.php │ │ │ ├── base.php │ │ │ └── main.php │ │ ├── site/ │ │ │ ├── error.php │ │ │ ├── index.php │ │ │ ├── login.php │ │ │ ├── requestPasswordResetToken.php │ │ │ ├── resendVerificationEmail.php │ │ │ ├── resetPassword.php │ │ │ └── signup.php │ │ └── video/ │ │ ├── _buttons.php │ │ ├── _comment_item.php │ │ ├── _video_item.php │ │ ├── history.php │ │ ├── index.php │ │ ├── search.php │ │ └── view.php │ └── web/ │ ├── assets/ │ │ └── .gitignore │ ├── css/ │ │ └── site.css │ ├── js/ │ │ └── app.js │ └── storage/ │ └── .gitignore ├── init ├── init.bat ├── requirements.php ├── sample.php ├── vagrant/ │ ├── config/ │ │ ├── .gitignore │ │ └── vagrant-local.example.yml │ ├── nginx/ │ │ ├── app.conf │ │ └── log/ │ │ └── .gitignore │ └── provision/ │ ├── always-as-root.sh │ ├── common.sh │ ├── once-as-root.sh │ └── once-as-vagrant.sh └── yii.bat ================================================ FILE CONTENTS ================================================ ================================================ FILE: .bowerrc ================================================ { "directory" : "vendor/bower-asset" } ================================================ FILE: .gitignore ================================================ # yii console commands /yii /yii_test /yii_test.bat # phpstorm project files .idea # netbeans project files nbproject # zend studio for eclipse project files .buildpath .project .settings # windows thumbnail cache Thumbs.db # composer vendor dir /vendor # composer itself is not needed composer.phar # Mac DS_Store Files .DS_Store # phpunit itself is not needed phpunit.phar # local phpunit config /phpunit.xml # vagrant runtime /.vagrant # ignore generated files /frontend/web/index.php /frontend/web/index-test.php /frontend/web/robots.txt /backend/web/index.php /backend/web/index-test.php /backend/web/robots.txt ================================================ FILE: LICENSE.md ================================================ Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Yii Software LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================

FreeCodeTube - Yii2 Youtube Clone


#### The project was created while recording [video for FreeCodeCamp](https://youtu.be/whuIf33v2Ug) Features ================ - Login and Registration - Email confirmation - Upload videos - Provide thumbnail, title, description, tags - Status of the video: Published or Unlisted - Dashboard with analitics: - Latest video - Number of total views - Number of total subscribers - Latest subscribers - View videos - Leave a like/dislike - Find similar videos - Channel page - View videos only for specific channel - Subscribe on channel or unsubscribe - Sending email when user subscribes to channel - Global search to search videos by title, description or tags - History page Demo ==== If you want to see working demo of the application [click here](https://freecodetube.thecodeholic.com/) Installation ============ ## Requirements The minimum requirement by this project template is that your Web server supports PHP 5.6.0. ## Installing using Composer ##### Clone the repository from github. git clone git@github.com:thecodeholic/Yii2-Youtube-Clone.git [YourDirectoryName] The command installs the project in a directory named `YourDirectoryName`. You can choose a different directory name if you want. ##### Install dependencies For this we need composer to be installed on our operating system. If you do not have [Composer](http://getcomposer.org/), follow the instructions in the [Installing Yii](https://github.com/yiisoft/yii2/blob/master/docs/guide/start-installation.md#installing-via-composer) section of the definitive guide to install it. With Composer installed, navigate to the project folder from command line and run composer install ## Preparing application Follow the steps from [yii2 advanced template](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/start-installation.md#preparing-application) to prepare installation. After doing all the steps from [yii2 advanced template](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/start-installation.md#preparing-application) open `common/config/params-local.php` and add your frontend domain on key `frontendUrl`. Example: ```php return [ 'frontendUrl' => 'http://frontend.test/' ]; ``` ================================================ FILE: Vagrantfile ================================================ require 'yaml' require 'fileutils' required_plugins = %w( vagrant-hostmanager vagrant-vbguest ) required_plugins.each do |plugin| exec "vagrant plugin install #{plugin}" unless Vagrant.has_plugin? plugin end domains = { frontend: 'y2aa-frontend.test', backend: 'y2aa-backend.test' } config = { local: './vagrant/config/vagrant-local.yml', example: './vagrant/config/vagrant-local.example.yml' } # copy config from example if local config not exists FileUtils.cp config[:example], config[:local] unless File.exist?(config[:local]) # read config options = YAML.load_file config[:local] # check github token if options['github_token'].nil? || options['github_token'].to_s.length != 40 puts "You must place REAL GitHub token into configuration:\n/yii2-app-advanced/vagrant/config/vagrant-local.yml" exit end # vagrant configurate Vagrant.configure(2) do |config| # select the box config.vm.box = 'bento/ubuntu-16.04' # should we ask about box updates? config.vm.box_check_update = options['box_check_update'] config.vm.provider 'virtualbox' do |vb| # machine cpus count vb.cpus = options['cpus'] # machine memory size vb.memory = options['memory'] # machine name (for VirtualBox UI) vb.name = options['machine_name'] end # machine name (for vagrant console) config.vm.define options['machine_name'] # machine name (for guest machine console) config.vm.hostname = options['machine_name'] # network settings config.vm.network 'private_network', ip: options['ip'] # sync: folder 'yii2-app-advanced' (host machine) -> folder '/app' (guest machine) config.vm.synced_folder './', '/app', owner: 'vagrant', group: 'vagrant' # disable folder '/vagrant' (guest machine) config.vm.synced_folder '.', '/vagrant', disabled: true # hosts settings (host machine) config.vm.provision :hostmanager config.hostmanager.enabled = true config.hostmanager.manage_host = true config.hostmanager.ignore_private_ip = false config.hostmanager.include_offline = true config.hostmanager.aliases = domains.values # provisioners config.vm.provision 'shell', path: './vagrant/provision/once-as-root.sh', args: [options['timezone']] config.vm.provision 'shell', path: './vagrant/provision/once-as-vagrant.sh', args: [options['github_token']], privileged: false config.vm.provision 'shell', path: './vagrant/provision/always-as-root.sh', run: 'always' # post-install message (vagrant console) config.vm.post_up_message = "Frontend URL: http://#{domains[:frontend]}\nBackend URL: http://#{domains[:backend]}" end ================================================ FILE: backend/Dockerfile ================================================ FROM yiisoftware/yii2-php:7.2-apache # Change document root for Apache RUN sed -i -e 's|/app/web|/app/backend/web|g' /etc/apache2/sites-available/000-default.conf ================================================ FILE: backend/assets/AppAsset.php ================================================ * @package backend\assets */ class TagsInputAsset extends AssetBundle { public $basePath = '@webroot/tagsinput'; public $baseUrl = '@web/tagsinput'; public $css = [ 'tagsinput.css' ]; public $js = [ 'tagsinput.js' ]; public $depends = [ JqueryAsset::class ]; } ================================================ FILE: backend/codeception.yml ================================================ namespace: backend\tests actor_suffix: Tester paths: tests: tests output: tests/_output data: tests/_data support: tests/_support bootstrap: _bootstrap.php settings: colors: true memory_limit: 1024M modules: config: Yii2: configFile: 'config/codeception-local.php' ================================================ FILE: backend/config/.gitignore ================================================ codeception-local.php main-local.php params-local.php test-local.php ================================================ FILE: backend/config/bootstrap.php ================================================ 'app-backend', 'name' => 'FreeCodeTube Studio', 'basePath' => dirname(__DIR__), 'controllerNamespace' => 'backend\controllers', 'bootstrap' => ['log'], 'modules' => [], 'language' => 'en-US', 'components' => [ 'request' => [ 'csrfParam' => '_csrf-backend', ], 'user' => [ 'identityClass' => 'common\models\User', 'enableAutoLogin' => true, 'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true], ], 'session' => [ // this is the name of the session cookie used for login on the backend 'name' => 'advanced-backend', ], 'log' => [ 'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning'], ], ], ], 'errorHandler' => [ 'errorAction' => 'site/error', ], 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [ 'video/update/' => 'video/update' ], ], 'assetManager' => [ 'appendTimestamp' => true ] ], 'params' => $params, ]; ================================================ FILE: backend/config/params.php ================================================ 'admin@example.com', ]; ================================================ FILE: backend/config/test.php ================================================ 'app-backend-tests', 'components' => [ 'assetManager' => [ 'basePath' => __DIR__ . '/../web/assets', ], 'urlManager' => [ 'showScriptName' => true, ], 'request' => [ 'cookieValidationKey' => 'test', ], ], ]; ================================================ FILE: backend/controllers/CommentController.php ================================================ [ 'class' => AccessControl::class, 'rules' => [ [ 'allow' => true, 'roles' => ['@'] ] ] ], 'verbs' => [ 'class' => VerbFilter::className(), 'actions' => [ 'delete' => ['POST'], ], ], ]; } /** * Lists all Comment models. * @return mixed */ public function actionIndex() { $searchModel = new CommentSearch(); $dataProvider = $searchModel->search(Yii::$app->request->queryParams, Yii::$app->user->id); return $this->render('index', [ 'searchModel' => $searchModel, 'dataProvider' => $dataProvider, ]); } /** * Displays a single Comment model. * @param integer $id * @return mixed * @throws NotFoundHttpException if the model cannot be found */ public function actionView($id) { return $this->render('view', [ 'model' => $this->findModel($id), ]); } /** * Creates a new Comment model. * If creation is successful, the browser will be redirected to the 'view' page. * @return mixed */ public function actionCreate() { $model = new Comment(); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } return $this->render('create', [ 'model' => $model, ]); } /** * Updates an existing Comment model. * If update is successful, the browser will be redirected to the 'view' page. * @param integer $id * @return mixed * @throws NotFoundHttpException if the model cannot be found */ public function actionUpdate($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } return $this->render('update', [ 'model' => $model, ]); } /** * Deletes an existing Comment model. * If deletion is successful, the browser will be redirected to the 'index' page. * @param integer $id * @return mixed * @throws NotFoundHttpException if the model cannot be found */ public function actionDelete($id) { $this->findModel($id)->delete(); return $this->redirect(['index']); } /** * Finds the Comment model based on its primary key value. * If the model is not found, a 404 HTTP exception will be thrown. * @param integer $id * @return Comment the loaded model * @throws NotFoundHttpException if the model cannot be found */ protected function findModel($id) { if (($model = Comment::findOne($id)) !== null) { return $model; } throw new NotFoundHttpException('The requested page does not exist.'); } } ================================================ FILE: backend/controllers/SiteController.php ================================================ [ 'class' => AccessControl::className(), 'rules' => [ [ 'actions' => ['login', 'error'], 'allow' => true, ], [ 'actions' => ['logout', 'index'], 'allow' => true, 'roles' => ['@'], ], ], ], 'verbs' => [ 'class' => VerbFilter::className(), 'actions' => [ 'logout' => ['post'], ], ], ]; } /** * {@inheritdoc} */ public function actions() { return [ 'error' => [ 'class' => 'yii\web\ErrorAction', ], ]; } /** * Displays homepage. * * @return string */ public function actionIndex() { $user = Yii::$app->user->identity; $userId = $user->id; $latestVideo = Video::find() ->latest() ->creator($userId) ->limit(1) ->one(); $numberOfView = VideoView::find() ->alias('vv') ->innerJoin(Video::tableName() . ' v', 'v.video_id = vv.video_id') ->andWhere(['v.created_by' => $userId]) ->count(); $numberOfSubscribers = Yii::$app->cache->get('subscribers-'.$userId); if (!$numberOfSubscribers) { $numberOfSubscribers = $user->getSubscribers()->count(); Yii::$app->cache->set('subscribers-'.$userId, $numberOfSubscribers); } $subscribers = Subscriber::find() ->with('user') ->andWhere(['channel_id' => $userId]) ->orderBy('created_at DESC') ->limit(3) ->all(); return $this->render('index', [ 'latestVideo' => $latestVideo, 'numberOfView' => $numberOfView, 'numberOfSubscribers' => $numberOfSubscribers, 'subscribers' => $subscribers, ]); } /** * Login action. * * @return string */ public function actionLogin() { $this->layout = 'auth'; if (!Yii::$app->user->isGuest) { return $this->goHome(); } $model = new LoginForm(); if ($model->load(Yii::$app->request->post()) && $model->login()) { return $this->goBack(); } else { $model->password = ''; return $this->render('login', [ 'model' => $model, ]); } } /** * Logout action. * * @return string */ public function actionLogout() { Yii::$app->user->logout(); return $this->goHome(); } } ================================================ FILE: backend/controllers/VideoController.php ================================================ [ 'class' => AccessControl::class, 'rules' => [ [ 'allow' => true, 'roles' => ['@'] ] ] ], 'verbs' => [ 'class' => VerbFilter::className(), 'actions' => [ 'delete' => ['POST'], ], ], ]; } /** * Lists all Video models. * * @return mixed */ public function actionIndex() { $dataProvider = new ActiveDataProvider([ 'query' => Video::find() ->creator(Yii::$app->user->id) ->latest(), ]); return $this->render('index', [ 'dataProvider' => $dataProvider, ]); } /** * Creates a new Video model. * If creation is successful, the browser will be redirected to the 'view' page. * * @return mixed */ public function actionCreate() { $model = new Video(); $model->video = UploadedFile::getInstanceByName('video'); if (Yii::$app->request->isPost && $model->save()) { return $this->redirect(['update', 'id' => $model->video_id]); } return $this->render('create', [ 'model' => $model, ]); } /** * Updates an existing Video model. * If update is successful, the browser will be redirected to the 'view' page. * * @param string $id * @return mixed * @throws NotFoundHttpException if the model cannot be found */ public function actionUpdate($id) { $model = $this->findModel($id); $model->thumbnail = UploadedFile::getInstanceByName('thumbnail'); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['update', 'id' => $model->video_id]); } return $this->render('update', [ 'model' => $model, ]); } /** * Deletes an existing Video model. * If deletion is successful, the browser will be redirected to the 'index' page. * * @param string $id * @return mixed * @throws \Throwable * @throws \yii\db\StaleObjectException * @throws \yii\web\NotFoundHttpException if the model cannot be found */ public function actionDelete($id) { $this->findModel($id)->delete(); return $this->redirect(['index']); } /** * Finds the Video model based on its primary key value. * If the model is not found, a 404 HTTP exception will be thrown. * * @param string $id * @return Video the loaded model * @throws NotFoundHttpException if the model cannot be found */ protected function findModel($id) { if (( $model = Video::findOne($id) ) !== null) { return $model; } throw new NotFoundHttpException('The requested page does not exist.'); } } ================================================ FILE: backend/models/.gitkeep ================================================ * ================================================ FILE: backend/models/CommentSearch.php ================================================ with('video') ->parent() ->byChannel($userId) ->latest(); // add conditions that should always apply here $dataProvider = new ActiveDataProvider([ 'query' => $query, ]); $this->load($params); if (!$this->validate()) { // uncomment the following line if you do not want to return any records when validation fails // $query->where('0=1'); return $dataProvider; } // grid filtering conditions $query->andFilterWhere([ 'id' => $this->id, 'parent_id' => $this->parent_id, 'pinned' => $this->pinned, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, 'created_by' => $this->created_by, ]); $query->andFilterWhere(['like', 'comment', $this->comment]) ->andFilterWhere(['like', 'video_id', $this->video_id]); return $dataProvider; } } ================================================ FILE: backend/runtime/.gitignore ================================================ * !.gitignore ================================================ FILE: backend/tests/_bootstrap.php ================================================ 'erau', 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI', // password_0 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne', 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490', 'created_at' => '1392559490', 'updated_at' => '1392559490', 'email' => 'sfriesen@jenkins.info', ], ]; ================================================ FILE: backend/tests/_output/.gitignore ================================================ * !.gitignore ================================================ FILE: backend/tests/_support/.gitignore ================================================ _generated ================================================ FILE: backend/tests/_support/FunctionalTester.php ================================================ [ 'class' => UserFixture::className(), 'dataFile' => codecept_data_dir() . 'login_data.php' ] ]; } /** * @param FunctionalTester $I */ public function loginUser(FunctionalTester $I) { $I->amOnPage('/site/login'); $I->fillField('Username', 'erau'); $I->fillField('Password', 'password_0'); $I->click('login-button'); $I->see('Logout (erau)', 'form button[type=submit]'); $I->dontSeeLink('Login'); $I->dontSeeLink('Signup'); } } ================================================ FILE: backend/tests/functional/_bootstrap.php ================================================ 'davert']); * ``` * * In Cests * * ```php * \Codeception\Util\Fixtures::get('user1'); * ``` */ ================================================ FILE: backend/tests/functional.suite.yml ================================================ suite_namespace: backend\tests\functional actor: FunctionalTester modules: enabled: - Yii2 ================================================ FILE: backend/tests/unit/_bootstrap.php ================================================ 'davert']); * ``` * * In Tests * * ```php * \Codeception\Util\Fixtures::get('user1'); * ``` */ ================================================ FILE: backend/tests/unit.suite.yml ================================================ suite_namespace: backend\tests\unit actor: UnitTester ================================================ FILE: backend/views/comment/_comment_item.php ================================================
createdBy) ?> formatter->asRelativeTime($model->created_at) ?> created_at !== $model->updated_at): ?> (edited)
mention): ?> mention ?> comment ?>
comments as $comment): ?> render('_comment_item', ['model' => $comment]) ?>
================================================ FILE: backend/views/comment/_form.php ================================================
field($model, 'comment')->textarea(['rows' => 6]) ?> field($model, 'video_id')->textInput(['maxlength' => true]) ?> field($model, 'parent_id')->textInput() ?> field($model, 'pinned')->textInput() ?> field($model, 'created_at')->textInput() ?> field($model, 'updated_at')->textInput() ?> field($model, 'created_by')->textInput() ?>
'btn btn-success']) ?>
================================================ FILE: backend/views/comment/_item.php ================================================
render('_comment_item', [ 'model' => $model ]) ?>
render('@backend/views/video/_video_item', [ 'model' => $model->video ]) ?>
================================================ FILE: backend/views/comment/_search.php ================================================ ================================================ FILE: backend/views/comment/create.php ================================================ title = 'Create Comment'; $this->params['breadcrumbs'][] = ['label' => 'Comments', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?>

title) ?>

render('_form', [ 'model' => $model, ]) ?>
================================================ FILE: backend/views/comment/index.php ================================================ title = 'Comments'; $this->params['breadcrumbs'][] = $this->title; ?>

title) ?>

render('_search', ['model' => $searchModel]); ?> $dataProvider, 'itemView' => '_item', 'pager' => [ 'class' => \yii\bootstrap4\LinkPager::class ], 'layout' => '
{items}
{pager}' ]); ?>
================================================ FILE: backend/views/comment/update.php ================================================ title = 'Update Comment: ' . $model->id; $this->params['breadcrumbs'][] = ['label' => 'Comments', 'url' => ['index']]; $this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]]; $this->params['breadcrumbs'][] = 'Update'; ?>

title) ?>

render('_form', [ 'model' => $model, ]) ?>
================================================ FILE: backend/views/comment/view.php ================================================ title = $model->id; $this->params['breadcrumbs'][] = ['label' => 'Comments', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; \yii\web\YiiAsset::register($this); ?>

title) ?>

$model->id], ['class' => 'btn btn-primary']) ?> $model->id], [ 'class' => 'btn btn-danger', 'data' => [ 'confirm' => 'Are you sure you want to delete this item?', 'method' => 'post', ], ]) ?>

$model, 'attributes' => [ 'id', 'comment:ntext', 'video_id', 'parent_id', 'pinned', 'created_at', 'updated_at', 'created_by', ], ]) ?>
================================================ FILE: backend/views/layouts/_header.php ================================================ Yii::$app->name, 'brandUrl' => Yii::$app->homeUrl, 'options' => ['class' => 'navbar-expand-lg navbar-light bg-light shadow-sm'], 'innerContainerOptions' => [ 'class' => 'container-fluid' ] ]); $menuItems = [ ['label' => 'Create', 'url' => ['/video/create']], ]; if (Yii::$app->user->isGuest) { $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; } else { $menuItems[] = [ 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', 'url' => ['/site/logout'], 'linkOptions' => [ 'data-method' => 'post' ] ]; } echo Nav::widget([ 'options' => ['class' => 'navbar-nav ml-auto'], 'items' => $menuItems, ]); NavBar::end(); ================================================ FILE: backend/views/layouts/_sidebar.php ================================================ ================================================ FILE: backend/views/layouts/auth.php ================================================ beginContent('@backend/views/layouts/base.php'); ?>
endContent() ?> ================================================ FILE: backend/views/layouts/base.php ================================================ beginPage() ?> registerCsrfMetaTags() ?> <?= Html::encode($this->title) ?> head() ?> beginBody() ?>
render('_header') ?>
endBody() ?> endPage() ?> ================================================ FILE: backend/views/layouts/main.php ================================================ beginContent('@backend/views/layouts/base.php'); ?>
render('_sidebar') ?>
endContent() ?> ================================================ FILE: backend/views/site/error.php ================================================ title = $name; ?>

title) ?>

The above error occurred while the Web server was processing your request.

Please contact us if you think this is a server error. Thank you.

================================================ FILE: backend/views/site/index.php ================================================ title = Yii::$app->name; ?>
title ?>

Likes: getLikes()->count() ?>
Views: getViews()->count() ?>

Edit
You don't have uploaded videos yet
Total Views

Total Subscribers

Latest Subscribers
user->username ?>
================================================ FILE: backend/views/site/login.php ================================================ title = 'Login'; $this->params['breadcrumbs'][] = $this->title; ?>

title) ?>

Please fill out the following fields to login:

'login-form']); ?> field($model, 'username')->textInput(['autofocus' => true]) ?> field($model, 'password')->passwordInput() ?> field($model, 'rememberMe')->checkbox() ?>
'btn btn-primary', 'name' => 'login-button']) ?>
================================================ FILE: backend/views/video/_form.php ================================================
['enctype' => 'multipart/form-data'] ]); ?>
errorSummary($model) ?> field($model, 'title')->textInput(['maxlength' => true]) ?> field($model, 'description')->textarea(['rows' => 6]) ?>
field($model, 'tags', [ 'inputOptions' => ['data-role' => 'tagsinput'] ])->textInput(['maxlength' => true]) ?>
Video Link
Open Video
Video Name
video_name ?>
field($model, 'status')->dropDownList($model->getStatusLabels()) ?>
'btn btn-success']) ?>
================================================ FILE: backend/views/video/_video_item.php ================================================
title ?>
description, 10) ?>
================================================ FILE: backend/views/video/create.php ================================================ title = 'Create Video'; $this->params['breadcrumbs'][] = ['label' => 'Videos', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?>

title) ?>


Drag and drop a file you want to upload

Your video will be private until you publish it

['enctype' => 'multipart/form-data'] ]) ?> errorSummary($model) ?>
================================================ FILE: backend/views/video/index.php ================================================ title = 'Videos'; $this->params['breadcrumbs'][] = $this->title; ?>

title) ?>

'btn btn-success']) ?>

$dataProvider, 'columns' => [ ['class' => 'yii\grid\SerialColumn'], [ 'attribute' => 'title', 'content' => function ($model) { return $this->render('_video_item', ['model' => $model]); } ], [ 'attribute' => 'status', 'content' => function ($model) { return $model->getStatusLabels()[$model->status]; } ], //'has_thumbnail', //'video_name', 'created_at:datetime', 'updated_at:datetime', //'created_by', [ 'class' => 'yii\grid\ActionColumn', 'buttons' => [ 'delete' => function ($url) { return Html::a('Delete', $url, [ 'data-method' => 'post', 'data-confirm' => 'Are you sure?' ]); } ] ], ], ]); ?>
================================================ FILE: backend/views/video/update.php ================================================ title = 'Update Video: ' . $model->title; $this->params['breadcrumbs'][] = ['label' => 'Videos', 'url' => ['index']]; $this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->video_id]]; $this->params['breadcrumbs'][] = 'Update'; ?>

title) ?>

render('_form', [ 'model' => $model, ]) ?>
================================================ FILE: backend/web/app.js ================================================ /** * Created by TheCodeholic on 4/17/2020. */ $(function () { 'use strict'; $('#videoFile').change(ev => { $(ev.target).closest('form').trigger('submit'); }) }); ================================================ FILE: backend/web/assets/.gitignore ================================================ * !.gitignore ================================================ FILE: backend/web/css/site.css ================================================ html, body { height: 100%; } main { flex: 1; } .content-wrapper{ flex: 1; } aside{ min-width: 200px; } aside .nav-pills .nav-link { border-radius: 0; color: #444444; } aside .nav-pills .nav-link:hover { background: rgba(0, 0, 0, 0.05); } aside .nav-pills .nav-link.active { background: rgba(0, 0, 0, 0.05); color: #b90000; border-left: 4px solid #b90000; } .upload-icon { width: 200px; height: 200px; border-radius: 50%; background: #e0e0e0; display: flex; align-items: center; justify-content: center; font-size: 70px; color: #454545; } .btn-file { position: relative; } .btn-file input { position: absolute; left: 0; right: 0; top: 0; bottom: 0; width: 100%; height: 100%; opacity: 0; } .comment-wrapper { flex: 1; } .comment-wrapper .dropdown-toggle::after { content: none; } ================================================ FILE: backend/web/tagsinput/tagsinput.css ================================================ /* * bootstrap-tagsinput v0.8.0 * */ .bootstrap-tagsinput { background-color: #fff; border: 1px solid #ccc; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); display: inline-block; padding: 4px 6px; color: #555; vertical-align: middle; border-radius: 4px; width: 100%; line-height: 22px; cursor: text; } .bootstrap-tagsinput input { border: none; box-shadow: none; outline: none; background-color: transparent; padding: 0 6px; margin: 0; width: auto; max-width: inherit; } .bootstrap-tagsinput.form-control input::-moz-placeholder { color: #777; opacity: 1; } .bootstrap-tagsinput.form-control input:-ms-input-placeholder { color: #777; } .bootstrap-tagsinput.form-control input::-webkit-input-placeholder { color: #777; } .bootstrap-tagsinput input:focus { border: none; box-shadow: none; } .bootstrap-tagsinput .badge { margin: 2px 0; padding:5px 8px; } .bootstrap-tagsinput .badge [data-role="remove"] { margin-left: 8px; cursor: pointer; } .bootstrap-tagsinput .badge [data-role="remove"]:after { content: "×"; padding: 0px 4px; background-color:rgba(0, 0, 0, 0.1); border-radius:50%; font-size:13px } .bootstrap-tagsinput .badge [data-role="remove"]:hover:after { background-color:rgba(0, 0, 0, 0.62);} .bootstrap-tagsinput .badge [data-role="remove"]:hover:active { box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } .tt-menu { position: absolute; top: 100%; left: 0; z-index: 1000; display: none; float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; list-style: none; font-size: 14px; background-color: #ffffff; border: 1px solid #cccccc; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); background-clip: padding-box; cursor: pointer; } .tt-suggestion { display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 1.428571429; color: #333333; white-space: nowrap; } .tt-suggestion:hover, .tt-suggestion:focus { color: #ffffff; text-decoration: none; outline: 0; background-color: #428bca; } ================================================ FILE: backend/web/tagsinput/tagsinput.js ================================================ /* * bootstrap-tagsinput v0.8.0 * */ (function ($) { "use strict"; var defaultOptions = { tagClass: function(item) { return 'badge badge-info'; }, focusClass: 'focus', itemValue: function(item) { return item ? item.toString() : item; }, itemText: function(item) { return this.itemValue(item); }, itemTitle: function(item) { return null; }, freeInput: true, addOnBlur: true, maxTags: undefined, maxChars: undefined, confirmKeys: [13, 44], delimiter: ',', delimiterRegex: null, cancelConfirmKeysOnEmpty: false, onTagExists: function(item, $tag) { $tag.hide().fadeIn(); }, trimValue: false, allowDuplicates: false, triggerChange: true, editOnBackspace: false }; /** * Constructor function */ function TagsInput(element, options) { this.isInit = true; this.itemsArray = []; this.$element = $(element); this.$element.addClass('sr-only'); this.isSelect = (element.tagName === 'SELECT'); this.multiple = (this.isSelect && element.hasAttribute('multiple')); this.objectItems = options && options.itemValue; this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : ''; this.inputSize = Math.max(1, this.placeholderText.length); this.$container = $('
'); this.$input = $('').appendTo(this.$container); this.$element.before(this.$container); this.build(options); this.isInit = false; } TagsInput.prototype = { constructor: TagsInput, /** * Adds the given item as a new tag. Pass true to dontPushVal to prevent * updating the elements val() */ add: function(item, dontPushVal, options) { var self = this; if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) return; // Ignore falsey values, except false if (item !== false && !item) return; // Trim value if (typeof item === "string" && self.options.trimValue) { item = $.trim(item); } // Throw an error when trying to add an object while the itemValue option was not set if (typeof item === "object" && !self.objectItems) throw("Can't add objects when itemValue option is not set"); // Ignore strings only containg whitespace if (item.toString().match(/^\s*$/)) return; // If SELECT but not multiple, remove current tag if (self.isSelect && !self.multiple && self.itemsArray.length > 0) self.remove(self.itemsArray[0]); if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter; var items = item.split(delimiter); if (items.length > 1) { for (var i = 0; i < items.length; i++) { this.add(items[i], true); } if (!dontPushVal) self.pushVal(self.options.triggerChange); return; } } var itemValue = self.options.itemValue(item), itemText = self.options.itemText(item), tagClass = self.options.tagClass(item), itemTitle = self.options.itemTitle(item); // Ignore items allready added var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; if (existing && !self.options.allowDuplicates) { // Invoke onTagExists if (self.options.onTagExists) { var $existingTag = $(".badge", self.$container).filter(function() { return $(this).data("item") === existing; }); self.options.onTagExists(item, $existingTag); } return; } // if length greater than limit if (self.items().toString().length + item.length + 1 > self.options.maxInputLength) return; // raise beforeItemAdd arg var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options}); self.$element.trigger(beforeItemAddEvent); if (beforeItemAddEvent.cancel) return; // register item in internal array and map self.itemsArray.push(item); // add a tag element var $tag = $('' + htmlEncode(itemText) + ''); $tag.data('item', item); self.findInputWrapper().before($tag); // Check to see if the tag exists in its raw or uri-encoded form var optionExists = ( $('option[value="' + encodeURIComponent(itemValue).replace(/"/g, '\\"') + '"]', self.$element).length || $('option[value="' + htmlEncode(itemValue).replace(/"/g, '\\"') + '"]', self.$element).length ); // add