mirror of
https://github.com/r4sas/recastin-panel
synced 2025-09-03 09:23:02 +00:00
Added registration
This commit is contained in:
parent
4e42a56a7f
commit
83d7ea4e7f
@ -33,4 +33,5 @@ JWT_PASSPHRASE=a758fddfbc878122f8b37259b8ea14c3
|
|||||||
## ReCast Enviroments
|
## ReCast Enviroments
|
||||||
NGINX_CONFIG_DIR=/opt/nginx-rtmp/conf/
|
NGINX_CONFIG_DIR=/opt/nginx-rtmp/conf/
|
||||||
APP_HOST="http://recast.in"
|
APP_HOST="http://recast.in"
|
||||||
NGINX_RESTART_COMMAND="systemctl reload nginx-rtmp"
|
NGINX_RELOAD_COMMAND="systemctl reload nginx-rtmp"
|
||||||
|
APP_REGISTRATION_ENABLED=false
|
@ -18,11 +18,12 @@ ReCast is a multi platform streaming tool written in PHP and uses nginx RTMP. Yo
|
|||||||
### Environment variable overview
|
### Environment variable overview
|
||||||
| Name | Description | Example |
|
| Name | Description | Example |
|
||||||
|-----------------------|-------------------------------------------------------------------|--------------------------------------------------|
|
|-----------------------|-------------------------------------------------------------------|--------------------------------------------------|
|
||||||
|
| APP_HOST | URL which is used in nginx rtmp conf, This address must be http | http://try.recast.in |
|
||||||
| APP_ENV | Which environment it runs | prod |
|
| APP_ENV | Which environment it runs | prod |
|
||||||
| DATABASE_URL | Database credentials as URL | DATABASE_URL=mysql://USER:PASS@HOST:3306/DB_NAME |
|
| DATABASE_URL | Database credentials as URL | DATABASE_URL=mysql://USER:PASS@HOST:3306/DB_NAME |
|
||||||
| NGINX_CONFIG_DIR | Folder where nginx.conf is located | /opt/nginx-rtmp/conf/ |
|
| NGINX_CONFIG_DIR | Folder where nginx.conf is located | /opt/nginx-rtmp/conf/ |
|
||||||
| APP_HOST | URL which is used in nginx rtmp conf, This address must be http | http://try.recast.in |
|
| NGINX_RELOAD_COMMAND | Reload command for nginx rtmp | systemctl reload nginx-rtmp |
|
||||||
| NGINX_RESTART_COMMAND | Reload command for nginx rtmp | systemctl reload nginx-rtmp |
|
| APP_REGISTRATION_ENABLED | Toggles registration form | true |
|
||||||
|
|
||||||
**Docker Setup will be following**
|
**Docker Setup will be following**
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@ security:
|
|||||||
user_db:
|
user_db:
|
||||||
entity: { class: App\Entity\User, property: username }
|
entity: { class: App\Entity\User, property: username }
|
||||||
firewalls:
|
firewalls:
|
||||||
|
settings:
|
||||||
|
pattern: ^/api/(settings|register)
|
||||||
|
security: false
|
||||||
|
|
||||||
login:
|
login:
|
||||||
pattern: ^/api/auth/login
|
pattern: ^/api/auth/login
|
||||||
stateless: true
|
stateless: true
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
parameters:
|
parameters:
|
||||||
locale: 'en'
|
locale: 'en'
|
||||||
appHost: '%env(APP_HOST)%'
|
appHost: '%env(APP_HOST)%'
|
||||||
nginxFolder: '%env(NGINX_CONFIG_DIR)%'
|
nginxConfigFolder: '%env(NGINX_CONFIG_DIR)%'
|
||||||
nginxRestartCommand: '%env(NGINX_RESTART_COMMAND)%'
|
nginxReloadCommand: '%env(NGINX_RELOAD_COMMAND)%'
|
||||||
|
registrationEnabled: '%env(APP_REGISTRATION_ENABLED)%'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# default configuration for services in *this* file
|
# default configuration for services in *this* file
|
||||||
@ -39,7 +40,7 @@ services:
|
|||||||
class: App\Component\NginxConfigGenerator
|
class: App\Component\NginxConfigGenerator
|
||||||
autowire: true
|
autowire: true
|
||||||
bind:
|
bind:
|
||||||
$nginxFolder: '%nginxFolder%'
|
$nginxFolder: '%nginxConfigFolder%'
|
||||||
$appHost: '%appHost%'
|
$appHost: '%appHost%'
|
||||||
|
|
||||||
# add more service definitions when explicit configuration is needed
|
# add more service definitions when explicit configuration is needed
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="loginWrapper">
|
<div class="loginWrapper">
|
||||||
<div class="sidebarBanner"></div>
|
<div class="sidebarBanner"></div>
|
||||||
<div class="loginForm">
|
<div class="loginForm" v-if="!showRegistration">
|
||||||
<h4>Login</h4>
|
<h4>Login</h4>
|
||||||
|
|
||||||
<div class="alert alert-danger" v-if="authFailed">Bad credentials</div>
|
<div class="alert alert-danger" v-if="authFailed">Bad credentials</div>
|
||||||
|
|
||||||
|
|
||||||
<form @submit="onLogin">
|
<form @submit="onLogin">
|
||||||
<fg-input type="text"
|
<fg-input type="text"
|
||||||
label="Username"
|
label="Username"
|
||||||
@ -24,6 +23,48 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary">Login</button>
|
<button class="btn btn-primary">Login</button>
|
||||||
|
|
||||||
|
<div v-if="settings.registrationEnabled">
|
||||||
|
<hr>
|
||||||
|
<div class="text-center">
|
||||||
|
<a @click="toggleRegistration" href="#">Create a new Account</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="loginForm" v-if="showRegistration">
|
||||||
|
<h4>Registration</h4>
|
||||||
|
|
||||||
|
<form @submit="onRegister">
|
||||||
|
<fg-input type="text"
|
||||||
|
label="Username"
|
||||||
|
placeholder="Username"
|
||||||
|
pattern=".{3,}"
|
||||||
|
v-model="register.username">
|
||||||
|
</fg-input>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Password</label>
|
||||||
|
<input type="password" class="form-control" pattern=".{6,}" placeholder="Password" v-model="register.password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Password Confirmation</label>
|
||||||
|
<input type="password" class="form-control" pattern=".{6,}" placeholder="Password Confirmation" v-model="register.passwordConfirm">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fg-input type="email"
|
||||||
|
label="Email"
|
||||||
|
placeholder="Email"
|
||||||
|
v-model="register.email">
|
||||||
|
</fg-input>
|
||||||
|
|
||||||
|
<button class="btn btn-primary">Register</button>
|
||||||
|
<hr>
|
||||||
|
<div class="text-center">
|
||||||
|
<a @click="toggleRegistration" href="#">I have already a account</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -33,6 +74,11 @@
|
|||||||
import Card from 'src/components/UIComponents/Cards/Card.vue'
|
import Card from 'src/components/UIComponents/Cards/Card.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mounted() {
|
||||||
|
this.axios.get('/settings').then(response => {
|
||||||
|
this.settings = response.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
Card,
|
Card,
|
||||||
PCheckbox
|
PCheckbox
|
||||||
@ -43,8 +89,18 @@
|
|||||||
_username: '',
|
_username: '',
|
||||||
_password: '',
|
_password: '',
|
||||||
},
|
},
|
||||||
|
register: {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
passwordConfirm: '',
|
||||||
|
email: ''
|
||||||
|
},
|
||||||
rememberMe: false,
|
rememberMe: false,
|
||||||
authFailed: false
|
authFailed: false,
|
||||||
|
settings: {
|
||||||
|
registrationEnabled: false
|
||||||
|
},
|
||||||
|
showRegistration: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -64,6 +120,25 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.$notify(
|
this.$notify(
|
||||||
|
{
|
||||||
|
component: notification,
|
||||||
|
icon: 'fa fa-exclamation-triangle',
|
||||||
|
horizontalAlign: 'right',
|
||||||
|
verticalAlign: 'top',
|
||||||
|
type: 'danger'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRegister: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (this.register.password !== this.register.passwordConfirm) {
|
||||||
|
const notification = {
|
||||||
|
template: `<span>Passwords are not equal</span>`
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$notify(
|
||||||
{
|
{
|
||||||
component: notification,
|
component: notification,
|
||||||
icon: 'fa fa-exclamation-triangle',
|
icon: 'fa fa-exclamation-triangle',
|
||||||
@ -71,8 +146,39 @@
|
|||||||
verticalAlign: 'top',
|
verticalAlign: 'top',
|
||||||
type: 'danger'
|
type: 'danger'
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
})
|
this.axios.post('/register', this.register).then(response => {
|
||||||
|
const notification = {
|
||||||
|
template: `<span>Registration was successfully. You can login now</span>`
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
component: notification,
|
||||||
|
icon: 'fa fa-exclamation-triangle',
|
||||||
|
horizontalAlign: 'right',
|
||||||
|
verticalAlign: 'top',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
this.toggleRegistration();
|
||||||
|
}).catch(error => {
|
||||||
|
const notification = {
|
||||||
|
template: `<span>${error.response.data.message}</span>`
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
component: notification,
|
||||||
|
icon: 'fa fa-exclamation-triangle',
|
||||||
|
horizontalAlign: 'right',
|
||||||
|
verticalAlign: 'top',
|
||||||
|
type: 'danger'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggleRegistration: function () {
|
||||||
|
this.showRegistration = !this.showRegistration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ class CronRunnerCommand extends Command implements ContainerAwareInterface
|
|||||||
{
|
{
|
||||||
if ($this->connection->fetchColumn('SELECT 1 FROM queue')) {
|
if ($this->connection->fetchColumn('SELECT 1 FROM queue')) {
|
||||||
$this->configGenerator->generate();
|
$this->configGenerator->generate();
|
||||||
system($this->container->getParameter('nginxRestartCommand'));
|
system($this->container->getParameter('nginxReloadCommand'));
|
||||||
|
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
$io->success('Configs generated, rtmp has been reloaded');
|
$io->success('Configs generated, rtmp has been reloaded');
|
||||||
|
@ -48,22 +48,24 @@ class SetupCommand extends Command
|
|||||||
$appHost = $io->ask('Please specify a http url where recast will be available', 'http://app.recast.in');
|
$appHost = $io->ask('Please specify a http url where recast will be available', 'http://app.recast.in');
|
||||||
$nginxFolder = $io->ask('Please specify the nginx folder where nginx rtmp is installed', '/opt/nginx-rtmp/conf/');
|
$nginxFolder = $io->ask('Please specify the nginx folder where nginx rtmp is installed', '/opt/nginx-rtmp/conf/');
|
||||||
$nginxReloadCommand = $io->ask('Please specify the command that should be executed to reload nginx rtmp', 'systemctl reload nginx-rtmp');
|
$nginxReloadCommand = $io->ask('Please specify the command that should be executed to reload nginx rtmp', 'systemctl reload nginx-rtmp');
|
||||||
|
$registerEnabled = $io->ask('Should the registration enabled? (true / false)', 'true');
|
||||||
|
|
||||||
if (parse_url($appHost, PHP_URL_SCHEME) !== 'http') {
|
if (parse_url($appHost, PHP_URL_SCHEME) !== 'http') {
|
||||||
throw new \RuntimeException('URL must be http due nginx-rtmp limitations');
|
throw new \RuntimeException('URL must be http due nginx-rtmp limitations');
|
||||||
}
|
}
|
||||||
|
|
||||||
$envs = [];
|
$envs = [];
|
||||||
|
$envs['APP_HOST'] = $appHost;
|
||||||
$envs['APP_ENV'] = 'prod';
|
$envs['APP_ENV'] = 'prod';
|
||||||
$envs['APP_SECRET'] = $this->generateRandomString();
|
$envs['APP_SECRET'] = $this->generateRandomString();
|
||||||
|
$envs['REGISTRATION_ENABLED'] = $registerEnabled;
|
||||||
$envs['MAILER_URL'] = 'null://localhost';
|
$envs['MAILER_URL'] = 'null://localhost';
|
||||||
$envs['JWT_PRIVATE_KEY_PATH'] = 'config/jwt/private.pem';
|
$envs['JWT_PRIVATE_KEY_PATH'] = 'config/jwt/private.pem';
|
||||||
$envs['JWT_PUBLIC_KEY_PATH'] = 'config/jwt/public.pem';
|
$envs['JWT_PUBLIC_KEY_PATH'] = 'config/jwt/public.pem';
|
||||||
$envs['JWT_PASSPHRASE'] = 'a758fddfbc878122f8b37259b8ea14c3';
|
$envs['JWT_PASSPHRASE'] = 'a758fddfbc878122f8b37259b8ea14c3';
|
||||||
$envs['DATABASE_URL'] = sprintf('mysql://%s:%s@%s:%s/%s', $user, $password, $host, $hostPort, $dbName);
|
$envs['DATABASE_URL'] = sprintf('mysql://%s:%s@%s:%s/%s', $user, $password, $host, $hostPort, $dbName);
|
||||||
$envs['NGINX_CONFIG_DIR'] = $nginxFolder;
|
$envs['NGINX_CONFIG_DIR'] = $nginxFolder;
|
||||||
$envs['APP_HOST'] = $appHost;
|
$envs['NGINX_RELOAD_COMMAND'] = $nginxReloadCommand;
|
||||||
$envs['NGINX_RESTART_COMMAND'] = $nginxReloadCommand;
|
|
||||||
|
|
||||||
$stringEnv = [];
|
$stringEnv = [];
|
||||||
foreach ($envs as $env => $value) {
|
foreach ($envs as $env => $value) {
|
||||||
|
@ -1,20 +1,36 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
use Symfony\Component\Config\Util\XmlUtils;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Index
|
||||||
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
|
*/
|
||||||
class Index extends Controller
|
class Index extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @Route(path="/", name="index")
|
* @Route(path="/", name="index")
|
||||||
* @author Soner Sayakci <shyim@posteo.de>
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index(): Response
|
||||||
{
|
{
|
||||||
return $this->render('index.twig');
|
return $this->render('index.twig');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route(path="/api/settings")
|
||||||
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
|
*/
|
||||||
|
public function settings(): JsonResponse
|
||||||
|
{
|
||||||
|
return new JsonResponse([
|
||||||
|
'registrationEnabled' => XmlUtils::phpize($this->container->getParameter('registrationEnabled'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
92
src/Controller/Register.php
Normal file
92
src/Controller/Register.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Doctrine\ORM\ORMException;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
use Symfony\Component\Config\Util\XmlUtils;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api")
|
||||||
|
* Class Register
|
||||||
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
|
*/
|
||||||
|
class Register extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var UserRepository
|
||||||
|
*/
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var UserPasswordEncoderInterface
|
||||||
|
*/
|
||||||
|
private $userPasswordEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register constructor.
|
||||||
|
* @param UserRepository $repository
|
||||||
|
* @param UserPasswordEncoderInterface $userPasswordEncoder
|
||||||
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
|
*/
|
||||||
|
public function __construct(UserRepository $repository, UserPasswordEncoderInterface $userPasswordEncoder)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->userPasswordEncoder = $userPasswordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route(path="/register")
|
||||||
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
|
* @param Request $request
|
||||||
|
* @return JsonResponse
|
||||||
|
*/
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
if (!$this->isRegistrationEnabled()) {
|
||||||
|
return new JsonResponse(['message' => 'Registration is disabled'], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->request->all();
|
||||||
|
|
||||||
|
if ($this->repository->findOneBy(['username' => $data['username']])) {
|
||||||
|
return new JsonResponse(['message' => 'Username is already taken'], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->repository->findOneBy(['email' => $data['email']])) {
|
||||||
|
return new JsonResponse(['message' => 'Email is already taken'], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$user = new User();
|
||||||
|
$user->setUsername($data['username']);
|
||||||
|
$user->setPassword($this->userPasswordEncoder->encodePassword($user, $data['password']));
|
||||||
|
$user->setEmail($data['email']);
|
||||||
|
|
||||||
|
$manager = $this->get('doctrine.orm.default_entity_manager');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$manager->persist($user);
|
||||||
|
$manager->flush();
|
||||||
|
} catch (ORMException $e) {
|
||||||
|
return new JsonResponse(['message' => $e->getMessage()], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
* @author Soner Sayakci <shyim@posteo.de>
|
||||||
|
*/
|
||||||
|
private function isRegistrationEnabled(): bool
|
||||||
|
{
|
||||||
|
return XmlUtils::phpize($this->container->getParameter('registrationEnabled'));
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
var Encore = require('@symfony/webpack-encore');
|
|
||||||
|
|
||||||
Encore
|
|
||||||
// the project directory where compiled assets will be stored
|
|
||||||
.setOutputPath('public/build/')
|
|
||||||
// the public path used by the web server to access the previous directory
|
|
||||||
.setPublicPath('/build')
|
|
||||||
.cleanupOutputBeforeBuild()
|
|
||||||
.enableSourceMaps(!Encore.isProduction())
|
|
||||||
// uncomment to create hashed filenames (e.g. app.abc123.css)
|
|
||||||
// .enableVersioning(Encore.isProduction())
|
|
||||||
|
|
||||||
// uncomment to define the assets of the project
|
|
||||||
// .addEntry('js/app', './assets/js/app.js')
|
|
||||||
// .addStyleEntry('css/app', './assets/css/app.scss')
|
|
||||||
|
|
||||||
// uncomment if you use Sass/SCSS files
|
|
||||||
// .enableSassLoader()
|
|
||||||
|
|
||||||
// uncomment for legacy applications that require $/jQuery as a global variable
|
|
||||||
// .autoProvidejQuery()
|
|
||||||
;
|
|
||||||
|
|
||||||
module.exports = Encore.getWebpackConfig();
|
|
Loading…
x
Reference in New Issue
Block a user