mirror of
https://github.com/r4sas/recastin-panel
synced 2025-08-31 16:02:07 +00:00
Added registration
This commit is contained in:
parent
4e42a56a7f
commit
83d7ea4e7f
@ -33,4 +33,5 @@ JWT_PASSPHRASE=a758fddfbc878122f8b37259b8ea14c3
|
||||
## ReCast Enviroments
|
||||
NGINX_CONFIG_DIR=/opt/nginx-rtmp/conf/
|
||||
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
|
||||
| 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 |
|
||||
| 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/ |
|
||||
| APP_HOST | URL which is used in nginx rtmp conf, This address must be http | http://try.recast.in |
|
||||
| NGINX_RESTART_COMMAND | Reload command for nginx rtmp | systemctl reload nginx-rtmp |
|
||||
| NGINX_RELOAD_COMMAND | Reload command for nginx rtmp | systemctl reload nginx-rtmp |
|
||||
| APP_REGISTRATION_ENABLED | Toggles registration form | true |
|
||||
|
||||
**Docker Setup will be following**
|
||||
|
||||
|
@ -3,6 +3,10 @@ security:
|
||||
user_db:
|
||||
entity: { class: App\Entity\User, property: username }
|
||||
firewalls:
|
||||
settings:
|
||||
pattern: ^/api/(settings|register)
|
||||
security: false
|
||||
|
||||
login:
|
||||
pattern: ^/api/auth/login
|
||||
stateless: true
|
||||
|
@ -3,8 +3,9 @@
|
||||
parameters:
|
||||
locale: 'en'
|
||||
appHost: '%env(APP_HOST)%'
|
||||
nginxFolder: '%env(NGINX_CONFIG_DIR)%'
|
||||
nginxRestartCommand: '%env(NGINX_RESTART_COMMAND)%'
|
||||
nginxConfigFolder: '%env(NGINX_CONFIG_DIR)%'
|
||||
nginxReloadCommand: '%env(NGINX_RELOAD_COMMAND)%'
|
||||
registrationEnabled: '%env(APP_REGISTRATION_ENABLED)%'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
@ -39,7 +40,7 @@ services:
|
||||
class: App\Component\NginxConfigGenerator
|
||||
autowire: true
|
||||
bind:
|
||||
$nginxFolder: '%nginxFolder%'
|
||||
$nginxFolder: '%nginxConfigFolder%'
|
||||
$appHost: '%appHost%'
|
||||
|
||||
# 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>
|
||||
<div class="loginWrapper">
|
||||
<div class="sidebarBanner"></div>
|
||||
<div class="loginForm">
|
||||
<div class="loginForm" v-if="!showRegistration">
|
||||
<h4>Login</h4>
|
||||
|
||||
<div class="alert alert-danger" v-if="authFailed">Bad credentials</div>
|
||||
|
||||
|
||||
<form @submit="onLogin">
|
||||
<fg-input type="text"
|
||||
label="Username"
|
||||
@ -24,6 +23,48 @@
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@ -33,6 +74,11 @@
|
||||
import Card from 'src/components/UIComponents/Cards/Card.vue'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
this.axios.get('/settings').then(response => {
|
||||
this.settings = response.data;
|
||||
})
|
||||
},
|
||||
components: {
|
||||
Card,
|
||||
PCheckbox
|
||||
@ -43,8 +89,18 @@
|
||||
_username: '',
|
||||
_password: '',
|
||||
},
|
||||
register: {
|
||||
username: '',
|
||||
password: '',
|
||||
passwordConfirm: '',
|
||||
email: ''
|
||||
},
|
||||
rememberMe: false,
|
||||
authFailed: false
|
||||
authFailed: false,
|
||||
settings: {
|
||||
registrationEnabled: false
|
||||
},
|
||||
showRegistration: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -64,6 +120,25 @@
|
||||
};
|
||||
|
||||
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,
|
||||
icon: 'fa fa-exclamation-triangle',
|
||||
@ -71,8 +146,39 @@
|
||||
verticalAlign: 'top',
|
||||
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')) {
|
||||
$this->configGenerator->generate();
|
||||
system($this->container->getParameter('nginxRestartCommand'));
|
||||
system($this->container->getParameter('nginxReloadCommand'));
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$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');
|
||||
$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');
|
||||
$registerEnabled = $io->ask('Should the registration enabled? (true / false)', 'true');
|
||||
|
||||
if (parse_url($appHost, PHP_URL_SCHEME) !== 'http') {
|
||||
throw new \RuntimeException('URL must be http due nginx-rtmp limitations');
|
||||
}
|
||||
|
||||
$envs = [];
|
||||
$envs['APP_HOST'] = $appHost;
|
||||
$envs['APP_ENV'] = 'prod';
|
||||
$envs['APP_SECRET'] = $this->generateRandomString();
|
||||
$envs['REGISTRATION_ENABLED'] = $registerEnabled;
|
||||
$envs['MAILER_URL'] = 'null://localhost';
|
||||
$envs['JWT_PRIVATE_KEY_PATH'] = 'config/jwt/private.pem';
|
||||
$envs['JWT_PUBLIC_KEY_PATH'] = 'config/jwt/public.pem';
|
||||
$envs['JWT_PASSPHRASE'] = 'a758fddfbc878122f8b37259b8ea14c3';
|
||||
$envs['DATABASE_URL'] = sprintf('mysql://%s:%s@%s:%s/%s', $user, $password, $host, $hostPort, $dbName);
|
||||
$envs['NGINX_CONFIG_DIR'] = $nginxFolder;
|
||||
$envs['APP_HOST'] = $appHost;
|
||||
$envs['NGINX_RESTART_COMMAND'] = $nginxReloadCommand;
|
||||
$envs['NGINX_RELOAD_COMMAND'] = $nginxReloadCommand;
|
||||
|
||||
$stringEnv = [];
|
||||
foreach ($envs as $env => $value) {
|
||||
|
@ -1,20 +1,36 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
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\Response;
|
||||
|
||||
/**
|
||||
* Class Index
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
class Index extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route(path="/", name="index")
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function index()
|
||||
public function index(): Response
|
||||
{
|
||||
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