first commit

This commit is contained in:
benjibennn
2023-12-22 12:35:55 +08:00
commit 9f89a732d6
872 changed files with 156291 additions and 0 deletions

12
wave/src/Announcement.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
class Announcement extends Model
{
public function users(){
return $this->belongsToMany('Wave\User');
}
}

36
wave/src/ApiKey.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
class ApiKey extends Model
{
protected $table = 'api_keys';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'user_id',
'name',
'key',
'last_used_at',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'last_used_at' => 'datetime'
];
public function user(){
return $this->belongsTo(config('auth.providers.users.model'));
}
}

12
wave/src/Category.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function posts(){
return $this->hasMany('Wave\Post');
}
}

18
wave/src/Facades/Wave.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace Wave\Facades;
use Illuminate\Support\Facades\Facade;
class Wave extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'wave';
}
}

View File

@@ -0,0 +1,171 @@
<?php
use App\Models\PermissionRole;
use App\Models\Company;
if (!class_exists(WaveKeyValueConvertible::class)) {
class WaveKeyValueConvertible
{
public function toObject() {
$array = (array)$this;
if (is_array($this)) {
return (object)$array;
}
return $this;
}
}
}
if (!class_exists(WaveKeyValueHelper::class)) {
class WaveKeyValueHelper extends WaveKeyValueConvertible
{
public $required = false;
public $field;
public $type;
public $details;
public $display_name;
public $options = [];
public static function create($type, $field, $details, $display_name, $required = 0, $options = []) {
$result = new WaveKeyValueHelper();
$result->type = $type;
$result->field = $field;
$result->details = $details;
$result->display_name = $display_name;
$result->required = $required;
$result->options = $options;
return $result;
}
public function getTranslatedAttribute($attribute) {
return $this->display_name;
}
}
}
if (!class_exists(WaveKeyValueTypeHelper::class)) {
class WaveKeyValueTypeHelper extends WaveKeyValueConvertible
{
protected $id = 0;
protected $key = null;
public function setKey($key, $content) {
$this->key = $key;
$this->{$key} = $content;
}
public static function create($key, $content) {
$result = new WaveKeyValueTypeHelper();
$result->setKey($key, $content);
return $result;
}
public function getKey() { return $this->key; }
}
}
if (!function_exists('wave_key_value')){
function wave_key_value($type, $key, $content = '', $details = '', $placeholder = '', $required = 0){
$row = WaveKeyValueHelper::create($type, $key, $details, $placeholder, $required);
$dataTypeContent = WaveKeyValueTypeHelper::create($key, $content);
$type = '<input type="hidden" value="' . $type . '" name="' . $key . '_type__wave_keyvalue">';
return app('voyager')->formField($row, '', $dataTypeContent->toObject()) . $details . $type;
}
}
if (!function_exists('profile_field')){
function profile_field($type, $key){
$value = auth()->user()->profile($key);
if($value){
return wave_key_value($type, $key, $value);
} else {
return wave_key_value($type, $key);
}
}
}
if(!function_exists('stringToColorCode')){
function stringToColorCode($str) {
$code = dechex(crc32($str));
$code = substr($code, 0, 6);
return $code;
}
}
if(!function_exists('tailwindPlanColor')){
function tailwindPlanColor($str) {
$code = dechex(crc32($str));
$code = substr($code, 0, 6);
return $code;
}
}
if(!function_exists('checkRoleHasPermission')){
function checkRoleHasPermission($permission_id, $role_id) {
$current_user = \Auth::user();
$permission = PermissionRole::where('role_id', $role_id)
->where('permission_id', $permission_id)
->where('company_id', $current_user->company_id)->first();
if ($permission) {
return true;
}
return false;
}
}
if(!function_exists('getSizeOfFile')){
function getSizeOfFile($file_name) {
if (! is_null($file_name)) {
return convertToReadableSize(Storage::disk('s3')->size('/test/' . $file_name));
}
return '0';
}
}
if(!function_exists('convertToReadableSize')){
function convertToReadableSize($size){
$base = log($size) / log(1024);
$suffix = array("", "KB", "MB", "GB", "TB");
$f_base = floor($base);
return round(pow(1024, $base - floor($base)), 1) . $suffix[$f_base];
}
}
if(!function_exists('getUserCompanies')){
function getUserCompanies(){
$current_user = \Auth::user();
return Company::where('id', $current_user->company_id)->get();
}
}
if(!function_exists('getCompanyDetails')){
function getCompanyDetails($company_id){
return Company::where('id', $company_id)->first();
}
}

View File

@@ -0,0 +1,264 @@
<?php
namespace Wave\Http\Controllers\API;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use TCG\Voyager\Http\Controllers\ContentTypes\Text;
use TCG\Voyager\Http\Controllers\Controller;
use TCG\Voyager\Http\Controllers\Traits\BreadRelationshipParser;
use TCG\Voyager\Models\DataType;
class ApiController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
use BreadRelationshipParser;
//*********************************************
// ____
// | _ \
// | |_) |
// | _ <
// | |_) |
// |____/
//
// API Browse our Data Type (B)READ
//
//*********************************************
public function browse(Request $request, $slug)
{
$dataType = Datatype::where('slug', '=', $slug)->first();
$authorized = auth()->user()->can('browse', app($dataType->model_name));
if(!$authorized){
abort(403, 'Unauthorized');
}
// Next Get or Paginate the actual content from the MODEL that corresponds to the slug DataType
if (strlen($dataType->model_name) != 0) {
$model = app($dataType->model_name);
$query = $model::select('*');
$relationships = $dataType->getRelationships([], $dataType);
// If a column has a relationship associated with it, we do not want to show that field
$this->removeRelationshipField($dataType, 'browse');
$dataTypeContent = call_user_func([$query->with($relationships)->orderBy($model->getKeyName(), 'DESC'), 'paginate']);
$dataTypeContent = $this->resolveRelations($dataTypeContent, $dataType);
} else {
// If Model doesn't exist, get data from table name
$dataTypeContent = call_user_func([DB::table($dataType->name), $getter]);
$model = false;
}
return response()->json($dataTypeContent);
}
//*********************************************
// _____
// | __ \
// | |__) |
// | _ /
// | | \ \
// |_| \_\
//
// API Read an item of our Data Type B(R)EAD
//
//*********************************************
public function read(Request $request, $slug, $id)
{
$slug = $this->getSlug($request);
$dataType = Datatype::where('slug', '=', $slug)->first();
$relationships = $dataType->getRelationships([], $dataType);
if (strlen($dataType->model_name) != 0) {
$model = app($dataType->model_name);
$dataTypeContent = call_user_func([$model->with($relationships), 'findOrFail'], $id);
} else {
// If Model doest exist, get data from table name
$dataTypeContent = DB::table($dataType->name)->where('id', $id)->first();
}
// Replace relationships' keys for labels and create READ links if a slug is provided.
$dataTypeContent = $this->resolveRelations($dataTypeContent, $dataType, true);
// If a column has a relationship associated with it, we do not want to show that field
$this->removeRelationshipField($dataType, 'read');
// Check permission
$this->authorize('read', $dataTypeContent);
// Check if BREAD is Translatable
$isModelTranslatable = is_bread_translatable($dataTypeContent);
return response()->json($dataTypeContent);
}
//*********************************************
// ______
// | ____|
// | |__
// | __|
// | |____
// |______|
//
// API Edit an item of our Data Type BR(E)AD
//
//*********************************************
public function edit(Request $request, $slug, $id)
{
$slug = $this->getSlug($request);
$dataType = Datatype::where('slug', '=', $slug)->first();
// Compatibility with Model binding.
$id = $id instanceof Model ? $id->{$id->getKeyName()} : $id;
$data = call_user_func([$dataType->model_name, 'findOrFail'], $id);
// Check permission
$this->authorize('edit', $data);
if(!$this->isValidJson($request->getContent())){
abort('400', 'Invalid JSON structure.');
}
$data = $this->insertUpdateData($request, $slug, $dataType->editRows, $data);
if(isset($data)){
return response()->json(['success' => true, 'data' => $data]);
} else{
abort('400', 'Could not update content, error with data received');
}
}
//*********************************************
//
// /\
// / \
// / /\ \
// / ____ \
// /_/ \_\
//
//
// API Add a new item of our Data Type BRE(A)D
//
//*********************************************
public function add(Request $request)
{
$slug = $this->getSlug($request);
$dataType = Datatype::where('slug', '=', $slug)->first();
// Check permission
$this->authorize('add', app($dataType->model_name));
if(!$this->isValidJson($request->getContent())){
abort('400', 'Invalid JSON structure.');
}
$data = $this->insertUpdateData($request, $slug, $dataType->addRows, new $dataType->model_name());
if(isset($data)){
return response()->json(['success' => true, 'data' => $data]);
} else{
abort('400', 'Could not add content, error with data received');
}
}
//*********************************************
// _____
// | __ \
// | | | |
// | | | |
// | |__| |
// |_____/
//
// API Delete an item BREA(D)
//
//*********************************************
public function delete(Request $request, $slug, $id)
{
$slug = $this->getSlug($request);
$dataType = Datatype::where('slug', '=', $slug)->first();
// Check permission
$this->authorize('delete', app($dataType->model_name));
$data = call_user_func([$dataType->model_name, 'findOrFail'], $id);
$res = $data->delete($id);
if ($res) {
return response()->json(['success' => true, 'message' => 'Successfully deleted']);
}
}
public function getSlug(Request $request)
{
if (isset($this->slug)) {
$slug = $this->slug;
} else {
$slug = $request->segment(2);
}
return $slug;
}
public function insertUpdateData($request, $slug, $rows, $data)
{
foreach ($rows as $row) {
$options = $row->details;
$content = $this->getContentBasedOnType($request, $slug, $row, $options);
if(isset($request->{$row->field})){
$data->{$row->field} = $content;
}
}
$data->save();
return $data;
}
public function getContentBasedOnType(Request $request, $slug, $row, $options = null)
{
return (new Text($request, $slug, $row, $options))->handle();
}
private function isValidJson($string) {
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
}

View File

@@ -0,0 +1,238 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Mail\ForgetPasswordOtp;
use App\Models\Company;
use App\Models\Role;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Tymon\JWTAuth\Facades\JWTAuth;
use Wave\ApiKey;
use Wave\Notifications\VerifyEmail;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login', 'token', 'register', 'getRoles', 'forgotPasswordSendOtp']]);
}
/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$user = JWTAuth::user();
if(!$user->verified){
auth()->guard('api')->logout();
return response()->json(['error' => 'Please verify your email before logging into your account.'], 401);
}
if(!in_array($user->role_id, [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE, Role::BOOKKEEPER_ROLE, Role::COMPANY_SECRETARY_ROLE])) {
auth()->guard('api')->logout();
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
/**
* Log the user out (Invalidate the token).
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth()->guard('api')->logout();
return response()->json(['message' => 'Successfully logged out']);
}
public function token(){
$request = app('request');
if(isset($request->key)){
$key = ApiKey::where('key', '=', $request->key)->first();
$key->update([
'last_used_at' => Carbon::now(),
]);
if(isset($key->id)){
return response()->json(['access_token' => JWTAuth::fromUser($key->user, ['exp' => config('wave.api.key_token_expires', 1)])]);
} else {
abort('400', 'Invalid Api Key');
}
} else {
abort('401', 'Unauthorized');
}
}
/**
* Refresh a token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
$token = JWTAuth::getToken();
return $this->respondWithToken(JWTAuth::refresh($token));
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
$user = JWTAuth::user();
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => env('JWT_TTL', 60),
'role_id' => $user->role_id,
]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'phone' => 'required|string',
'password' => 'required|string|min:6|confirmed',
'role_id' => 'required|int',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$emailExists = User::where('email', $request['email'])->first();
if ($emailExists) {
return response()->json(['error' => 'Email already exists!'], 403);
}
$verification_code = Str::random(30);
$verified = true;
$username = null;
if(isset($request['username']) && !empty($request['username'])){
$username = $request['username'];
} elseif(isset($request['name']) && !empty($request['name'])) {
$username = Str::slug($request['name']);
} else {
$username = $this->getUniqueUsernameFromEmail($request['email']);
}
$username_original = $username;
$counter = 1;
while(User::where('username', '=', $username)->first()){
$username = $username_original . (string)$counter;
$counter += 1;
}
$company = Company::create([
'email' => $request['company_email'],
]);
$user = User::create([
'first_name' => $request['first_name'],
'last_name' => $request['last_name'],
'name' => $request['first_name'] . ' ' . $request['last_name'],
'email' => $request['email'],
'username' => $username,
'password' => bcrypt($request['password']),
'role_id' => $request['role_id'],
'verification_code' => $verification_code,
'verified' => $verified,
'trial_ends_at' => null,
'company_id' => $company ? $company->id : null,
'phone' => $request['phone'],
]);
if(!$verified){
$this->sendVerificationEmail($user);
}
$credentials = ['email' => $request['email'], 'password' => $request['password']];
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
public function getUniqueUsernameFromEmail($email)
{
$username = strtolower(trim(Str::slug(explode('@', $email)[0])));
$new_username = $username;
$user_exists = User::where('username', '=', $username)->first();
$counter = 1;
while (isset($user_exists->id) ) {
$new_username = $username . $counter;
$counter += 1;
$user_exists = User::where('username', '=', $new_username)->first();
}
$username = $new_username;
if(strlen($username) < 4){
$username = $username . uniqid();
}
return strtolower($username);
}
public function getRoles()
{
$roles = Role::whereIn('id', [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE])->get();
return response()->json([
'message' => 'User roles has successfully retrieved!',
'roles' => $roles,
]);
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
}
private function sendVerificationEmail($user){
Notification::route('mail', $user->email)->notify(new VerifyEmail($user));
}
}

View File

@@ -0,0 +1,111 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Models\ServiceChat;
use App\Models\ServiceChatMessage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\Facades\JWTAuth;
class ChatController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api');
}
public function getChatMessages(Request $request)
{
$validator = Validator::make($request->all(), [
'service_type' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$user = JWTAuth::user();
$newCollection = collect();
$chat = ServiceChat::where('company_id', $user->company_id)
->where('user_id', $user->id)
->where('service_type', $request->service_type)
->first();
$messages = $chat ? $chat->messages : null;
if ($messages) {
$newCollection = $messages->map(function ($message) use ($user) {
$message->date = $message->created_at->format('Y-m-d');
$message->is_own_message = $user->id == $message->from_user_id ? true : false;
$message->elapsed_time = $message->elapsed_time;
$message->message = $message->is_file ? '<a href="' . $message->file_url . '" target="_blank">' . $message->file_name . '</a>' : $message->message;
return $message;
})
->groupBy('date')
->map(function ($message) {
return $message->flatmap(function ($item) use ($message) {
return [
'date' => $item->created_at->format('d F, Y'),
'messages' => $message,
];
});
})
->values()
->all();
}
return response()->json([
'message' => 'Chat messages has successfully retrieved!',
'data' => $newCollection,
]);
}
public function sendChat(Request $request)
{
$validator = Validator::make($request->all(), [
'chat_service_type' => 'required',
'chat_message' => 'required_without:chat_message_file',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$user = JWTAuth::user();
$chat = ServiceChat::where('company_id', $user->company_id)
->where('user_id', $user->id)
->where('service_type', $request->chat_service_type)
->first();
if (! $chat) {
$chat = new ServiceChat();
$chat->company_id = $user->company_id;
$chat->user_id = $user->id;
$chat->service_type = $request->chat_service_type;
$chat->save();
}
$messageFileName = '';
if ($request->hasFile('chat_message_file')) {
$file = $request->file('chat_message_file');
$messageFileName = $request->file('chat_message_file')->getClientOriginalName();
$file->storePubliclyAs($chat->folder_path, $messageFileName);
}
ServiceChatMessage::create([
'service_chat_id' => $chat->id,
'message' => $request->chat_message,
'from_user_id' => $user->id,
'to_admin' => true,
'is_file' => $messageFileName ? true : false,
'file_name' => $messageFileName,
]);
return response()->json([
'message' => 'Chat message has successfully sent!',
]);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Mail\ForgetPasswordOtp;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Tymon\JWTAuth\Facades\JWTAuth;
use Wave\ApiKey;
use Wave\Notifications\VerifyEmail;
use Illuminate\Support\Facades\Storage;
class FileController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('auth:api');
}
public function storeFile(Request $request)
{
if ($request->hasFile('file')) {
$file = $request->file('file');
$originalFileName = $file->getClientOriginalName();
$sanitizedFileName = str_replace(' ', '_', $originalFileName); // Replac
$fileName = time() . '_' . $sanitizedFileName;
// Store the file in the 'test' directory in your S3 bucket
$filePath = 'test/' . $fileName;
Storage::disk('s3')->put($filePath, file_get_contents($file), 'public');
// Generate the URL
$url = env('AWS_ENDPOINT').env('AWS_BUCKET').'/'.$filePath;
return response()->json(['url' => $url], 200);
}
return response()->json(['message' => 'No file uploaded'], 400);
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Mail\ForgetPasswordOtp;
use App\Models\Company;
use App\Models\Role;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Tymon\JWTAuth\Facades\JWTAuth;
use Wave\ApiKey;
use Wave\Notifications\VerifyEmail;
class ForgotPasswordController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api');
}
public function sendOtp(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$user = User::where('email', $request->email)->first();
if (!$user) {
return response()->json(['error' => "Account doesn't exists!"], 403);
}
$otp = null;
while (true) {
$otp = random_int(100000, 999999);
$otpExists = User::where('forgot_password_otp', $otp)->first();
if (!$otpExists) {
break;
}
}
$user->forgot_password_otp = $otp;
$user->save();
Mail::to($request->email)->send(new ForgetPasswordOtp($otp));
return response()->json(['message' => 'OTP has successfully sent!']);
}
public function submitOtp(Request $request)
{
$validator = Validator::make($request->all(), [
'otp' => 'required|string|max:6',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$user = User::where('forgot_password_otp', $request->otp)->first();
if (!$user) {
return response()->json(['error' => 'Wrong OTP'], 403);
}
$user->forgot_password_otp = null;
$user->save();
return response()->json([
'message' => 'success',
'user_id' => $user->id,
]);
}
public function resetPassword(Request $request)
{
$validator = Validator::make($request->all(), [
'user_id' => 'required',
'password' => 'required|string|min:6|confirmed',
], [
'password.confirmed' => 'Wrong Password',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$user = User::find($request->user_id);
if (!$user) {
return response()->json(['error' => "User doesn't exists!"], 403);
}
$user->password = bcrypt($request->password);
$user->save();
return response()->json(['message' => 'Password has successfully reset']);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
class PrivacyPolicyController extends Controller
{
public function index()
{
$siteSetting = SiteSetting::latest()->first();
return response()->json([
'message' => 'Terms and conditions has successfully retrieved!',
'privacy_policy' => $siteSetting ? $siteSetting->privacy_policy : '',
]);
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\UserNotificationSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\Facades\JWTAuth;
class SettingsController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api');
}
public function changePassword(Request $request)
{
$validator = Validator::make($request->all(), [
'password' => 'required',
'new_password' => 'required|confirmed',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$current_user = JWTAuth::user();
$new_password = \Hash::make($request->get('new_password'));
if (! \Hash::check($request->get('password'), $current_user->password)) {
return response()->json(['error' => 'Invalid current password.'], 403);
}
User::where('id', $current_user->id)->update([
'password' => $new_password,
]);
return response()->json([
'message' => 'Password successfully changed.',
]);
}
public function getNotificationSettings()
{
$current_user = JWTAuth::user();
return response()->json([
'message' => 'Terms and conditions has successfully retrieved!',
'notification_settings' => [
'user_push_notification' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_PUSH_NOTIFICATION)->where('is_active', true)->exists(),
'user_bookkeeping_queue' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_BOOKKEEPING_QUEUE)->where('is_active', true)->exists(),
'user_company_security_queue' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_COMPANY_SECURTY_QUEUE)->where('is_active', true)->exists(),
'user_chat_room' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_CHAT_ROOM)->where('is_active', true)->exists(),
],
]);
}
public function toggleNotificationStatus(Request $request)
{
$validator = Validator::make($request->all(), [
'notification' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
$current_user = JWTAuth::user();
$set_status = true;
$check_settings = UserNotificationSetting::where('user_id', $current_user->id)->where('notification', $request->notification)->first();
if ($check_settings) {
$set_status = !$check_settings->is_active;
}
UserNotificationSetting::updateOrCreate(
[
'user_id' => $current_user->id,
'notification' => $request->notification,
],
[
'is_active' => $set_status,
],
);
return response()->json([
'message' => 'Notification status successfully updated',
]);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Wave\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
class TermsAndConditionsController extends Controller
{
public function index()
{
$siteSetting = SiteSetting::latest()->first();
return response()->json([
'message' => 'Terms and conditions has successfully retrieved!',
'terms_and_conditions' => $siteSetting ? $siteSetting->terms_and_conditions : '',
]);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Wave\Http\Controllers\Account;
use App\Http\Controllers\Controller;
class AccountController extends Controller
{
public function myAccount()
{
return view('theme::account.my-account');
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
use Wave\Announcement;
class AnnouncementController extends Controller
{
public function index(){
$announcements = Announcement::paginate(10);
return view('theme::announcements.index', compact('announcements'));
}
public function announcement($id){
$announcement = Announcement::find($id);
return view('theme::announcements.announcement', compact('announcement'));
}
public function read(){
$user = auth()->user();
$announcements = Announcement::all();
foreach($announcements as $announcement){
if(!$user->announcements()->where('id', $announcement->id)->exists()){
$user->announcements()->attach($announcement->id);
}
}
}
}

View File

@@ -0,0 +1,153 @@
<?php
namespace Wave\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Mail\ForgetPasswordOtp;
use App\Models\User;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Mail;
use Illuminate\Http\Request;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\Http\Response
*/
public function showLinkRequestForm()
{
return view('theme::auth.passwords.email');
}
public function showRequestForm()
{
// return view('theme::auth.passwords.email');
return view('theme::auth.passwords.user-reset');
}
public function sendOtp(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
$user = User::where('email', $request->email)->first();
if (!$user) {
return response()->json([
'success' => false,
'message' => "Account doesn't exists!",
]);
}
$otp = null;
while (true) {
$otp = random_int(100000, 999999);
$otpExists = User::where('forgot_password_otp', $otp)->first();
if (!$otpExists) {
break;
}
}
$user->forgot_password_otp = $otp;
$user->save();
Mail::to($request->email)->send(new ForgetPasswordOtp($otp));
return response()->json([
'success' => true,
]);
}
public function submitOtp(Request $request)
{
$validator = Validator::make($request->all(), [
'otp' => 'required|string|max:6',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
$user = User::where('forgot_password_otp', $request->otp)->first();
if (!$user) {
return response()->json([
'success' => false,
'message' => 'Wrong OTP',
]);
}
$user->forgot_password_otp = null;
$user->save();
return response()->json([
'success' => true,
'user_id' => $user->id,
]);
}
public function resetPassword(Request $request)
{
$validator = Validator::make($request->all(), [
'user_id' => 'required',
'password' => 'required|string|min:6|confirmed',
], [
'password.confirmed' => 'Wrong Password',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
$user = User::find($request->user_id);
if (!$user) {
return response()->json([
'success' => false,
'message' => "User doesn't exists!",
]);
}
$user->password = bcrypt($request->password);
$user->save();
return response()->json([
'success' => true,
'message' => 'Password has successfully reset'
]);
}
}

View File

@@ -0,0 +1,198 @@
<?php
namespace Wave\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Role;
use App\Models\User;
use App\Models\SiteSetting;
use App\Models\UserAccessLog;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/cms/dashboard';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function username(){
if(setting('auth.email_or_username')){
return setting('auth.email_or_username');
}
return 'email';
}
public function showLoginForm()
{
return view('theme::auth.user-login');
}
protected function authenticated(Request $request, $user)
{
if(!$user->verified){
$this->guard()->logout();
return redirect()->back()->with(['message' => 'Please verify your email before logging into your account.', 'message_type' => 'warning']);
}
if ($request->user_type == 'user') {
if ($user->status == 'inactive'){
$this->guard()->logout();
return redirect()->back()->with(['message' => 'User is currently deactivated.', 'message_type' => 'warning']);
}
if (!in_array($user->role_id, [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE, Role::BOOKKEEPER_ROLE, Role::COMPANY_SECRETARY_ROLE])) {
$this->guard()->logout();
return redirect()->back()->with(['message' => 'Wrong Email or Password', 'message_type' => 'warning']);
}
}
if ($request->user_type == 'admin') {
if ($user->status == 'inactive'){
$this->guard()->logout();
return redirect()->back()->withErrors(['email' => 'User is currently deactivated.']);
}
if(!in_array($user->role_id, [Role::IT_PERSONNEL_ROLE, Role::NUMSTATION_MANAGER_ROLE, Role::NUMSTATION_STAFF_ROLE])) {
$this->guard()->logout();
return redirect()->back()->withErrors(['email' => 'These credentials do not match our records.']);
}
}
UserAccessLog::create([
'user_id' => $user->id,
'event' => 'Login',
'description' => 'Login to [' . $user->email . ']',
'status' => 'success',
]);
}
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended(Auth::user()->getRedirectRoute())->with(['message' => 'Successfully logged in.', 'message_type' => 'success']);
}
protected function sendFailedLoginResponse(Request $request)
{
if($request->user_type == 'user') {
return redirect()->back()->with(['message' => 'Wrong Email or Password', 'message_type' => 'warning']);
}
else {
return redirect()->back()->withErrors(['email' => 'These credentials do not match our records.']);
}
}
public function logout()
{
$user = auth()->user();
UserAccessLog::create([
'user_id' => $user->id,
'event' => 'Logout',
'description' => 'Logout [' . $user->email . ']',
'status' => 'success',
]);
Auth::logout();
return redirect($user->getRedirectRouteIfNotAuthenticated());
}
public function showAdminLoginForm()
{
return view('theme::auth.login');
}
public function termsAndConditions()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::auth.terms-and-conditions', [
'siteSetting' => $siteSetting,
]);
}
public function privacyPolicy()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::auth.privacy-policy', [
'siteSetting' => $siteSetting,
]);
}
public function apiLogin(Request $request)
{
$validate = Validator::make($request->all(), [
'email' => 'required',
'password' => 'required',
]);
if ($validate->fails()) {
return response()->json([
'status' => false,
'message' => $validate->messages(),
]);
}
$user = User::where('email', $request->email)->first();
if ($user) {
if (\Hash::check($request->password, $user->password)) {
$token = \Str::random(60);
$user->forceFill([
'api_token' => hash('sha256', $token),
])->save();
return response()->json([
'status' => true,
'user' => array(
'id' => $user->id,
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'email' => $user->email,
'username' => $user->username,
'api_token' => $token,
),
]);
}
}
return response()->json([
'status' => false,
'message' => 'Invalid Email or Password',
]);
}
}

View File

@@ -0,0 +1,427 @@
<?php
namespace Wave\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\InviteUser;
use App\Models\User;
use App\Models\Role as AppRole;
use App\Models\Company;
use Carbon\Carbon;
use Illuminate\Auth\Events\Registered;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use TCG\Voyager\Models\Role;
use Wave\Notifications\VerifyEmail;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = '/dashboard';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' =>
[
'complete'
]]);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
$validatorArray = [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'phone' => 'required|string',
'password' => 'required|string|min:6|confirmed',
'role_id' => 'required|int',
];
if (!isset($data['invite_token'])) {
$validatorArray['company_email'] = 'required|string|email|max:255';
}
return Validator::make($data, $validatorArray);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
public function create(array $data)
{
// $verification_code = NULL;
// $verified = 1;
// if(setting('auth.verify_email', false)){
$verification_code = Str::random(30);
$verified = false;
// }
$username = null;
if(isset($data['username']) && !empty($data['username'])){
$username = $data['username'];
} elseif(isset($data['name']) && !empty($data['name'])) {
$username = Str::slug($data['name']);
} else {
$username = $this->getUniqueUsernameFromEmail($data['email']);
}
$username_original = $username;
$counter = 1;
while(User::where('username', '=', $username)->first()){
$username = $username_original . (string)$counter;
$counter += 1;
}
// $trial_days = setting('billing.trial_days', 14);
// $trial_ends_at = null;
// // if trial days is not zero we will set trial_ends_at to ending date
// if(intval($trial_days) > 0){
// $trial_ends_at = now()->addDays(setting('billing.trial_days', 14));
// }
$company = null;
if (isset($data['invite_token'])) {
$inviteUser = InviteUser::where('token', $data['invite_token'])->first();
if ($inviteUser) {
$inviteUser->is_used = true;
$inviteUser->save();
$company = Company::find($inviteUser->company_id);
$verified = true;
}
}
else {
$company = Company::create([
'email' => $data['company_email'],
]);
}
$user = User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'name' => $data['first_name'] . ' ' . $data['last_name'],
'email' => $data['email'],
'username' => $username,
'password' => bcrypt($data['password']),
'role_id' => $data['role_id'],
'verification_code' => $verification_code,
'verified' => $verified,
'trial_ends_at' => null,
'company_id' => $company ? $company->id : null,
'phone' => $data['phone'],
]);
if(!$verified){
$this->sendVerificationEmail($user);
}
return $user;
}
/**
* Complete a new user registration after they have purchased
*
* @param Request $request
* @return redirect
*/
public function complete(Request $request){
if(setting('auth.username_in_registration') && setting('auth.username_in_registration') == 'yes'){
$request->validate([
'name' => 'required|string|min:3|max:255',
'username' => 'required|string|max:20|unique:users,username,' . auth()->user()->id,
'password' => 'required|string|min:6'
]);
} else {
$request->validate([
'name' => 'required|string|min:3|max:255',
'password' => 'required|string|min:6'
]);
}
// Update the user info
$user = auth()->user();
$user->name = $request->name;
$user->username = $request->username;
$user->password = bcrypt($request->password);
$user->save();
return redirect()->route('wave.dashboard')->with(['message' => 'Successfully updated your profile information.', 'message_type' => 'success']);
}
private function sendVerificationEmail($user){
$company = Company::where('id', $user->company_id)->first();
Notification::route('mail', $company->email)->notify(new VerifyEmail($user));
}
public function showRegistrationForm()
{
// if(setting('billing.card_upfront')){
// return redirect()->route('wave.pricing');
// }
// return view('theme::auth.register');
$token = request()->token ? request()->token : null;
$inviteEmail = null;
$roles = null;
if ($token) {
$inviteUser = InviteUser::where('token', $token)->first();
if (!$inviteUser) {
abort(404);
}
if ($inviteUser->is_used) {
abort(404);
}
$userExists = User::where('email', $inviteUser->email)->first();
if ($userExists) {
abort(404);
}
$inviteEmail = $inviteUser->email;
$roles = AppRole::whereIn('id', [AppRole::BOOKKEEPER_ROLE, AppRole::COMPANY_SECRETARY_ROLE])->get();
}
else {
$roles = AppRole::whereIn('id', [AppRole::OWNER_ROLE, AppRole::ADMINISTRATOR_ROLE])->get();
}
return view('theme::auth.user-register', [
'roles' => $roles,
'invite_token' => $token,
'invite_email' => $inviteEmail,
]);
}
public function verify(Request $request, $verification_code){
$user = User::where('verification_code', '=', $verification_code)->first();
if ($user) {
$user->verification_code = NULL;
$user->verified = 1;
$user->email_verified_at = Carbon::now();
$user->save();
return view('theme::auth.verified');
}
// return redirect()->route('login')->with(['message' => 'Successfully verified your email. You can now login.', 'message_type' => 'success']);
return redirect()->route('login')->with(['message' => 'Verification code expired', 'message_type' => 'error']);
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
if(setting('auth.verify_email')){
// send email verification
return redirect()->route('login')->with(['message' => 'Thanks for signing up! Please check your email to verify your account.', 'message_type' => 'success']);
} else {
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath())->with(['message' => 'Thanks for signing up!', 'message_type' => 'success']);
}
}
public function registerAjax(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
event(new Registered($user = $this->create($request->all())));
return response()->json([
'success' => true,
'message' => 'Thanks for signing up! Please check your email to verify your account.',
]);
}
}
public function getUniqueUsernameFromEmail($email)
{
$username = strtolower(trim(Str::slug(explode('@', $email)[0])));
$new_username = $username;
$user_exists = User::where('username', '=', $username)->first();
$counter = 1;
while (isset($user_exists->id) ) {
$new_username = $username . $counter;
$counter += 1;
$user_exists = User::where('username', '=', $new_username)->first();
}
$username = $new_username;
if(strlen($username) < 4){
$username = $username . uniqid();
}
return strtolower($username);
}
public function registerUser(Request $request)
{
$validate = Validator::make($request->all(), [
'first_name' => 'required',
'last_name' => 'required',
'username' => 'required',
'email' => 'required|unique:users',
'company_email' => 'required',
'password' => 'required',
'phone' => 'required',
'role_id' => 'required',
]);
if ($validate->fails()) {
return response()->json([
'status' => false,
'message' => $validate->messages(),
]);
}
$data = $request->all();
$verification_code = Str::random(30);
$verified = false;
$username = null;
if(isset($data['username']) && !empty($data['username'])){
$username = $data['username'];
} elseif(isset($data['name']) && !empty($data['name'])) {
$username = Str::slug($data['name']);
} else {
$username = $this->getUniqueUsernameFromEmail($data['email']);
}
$username_original = $username;
$counter = 1;
while(User::where('username', '=', $username)->first()){
$username = $username_original . (string)$counter;
$counter += 1;
}
$company = null;
if (isset($data['invite_token'])) {
$inviteUser = InviteUser::where('token', $data['invite_token'])->first();
if ($inviteUser) {
$inviteUser->is_used = true;
$inviteUser->save();
$company = Company::find($inviteUser->company_id);
$verified = true;
}
}
else {
$company = Company::create([
'email' => $data['company_email'],
]);
}
$token = Str::random(60);
$user = User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'name' => $data['first_name'] . ' ' . $data['last_name'],
'email' => $data['email'],
'username' => $username,
'password' => bcrypt($data['password']),
'role_id' => $data['role_id'],
'verification_code' => $verification_code,
'verified' => $verified,
'trial_ends_at' => null,
'company_id' => $company ? $company->id : null,
'phone' => $data['phone'],
'api_token' => hash('sha256', $token),
]);
if(!$verified){
// $this->sendVerificationEmail($user);
}
return response()->json([
'status' => true,
'message' => 'user successfully created and send verification code on the email'
]);
}
public function verifyEmail(Request $request){
$validate = Validator::make($request->all(), [
'verification_code' => 'required',
]);
if ($validate->fails()) {
return response()->json([
'status' => false,
'message' => $validate->messages(),
]);
}
$user = User::where('verification_code', '=', $request->verification_code)->first();
if ($user) {
$user->verification_code = NULL;
$user->verified = 1;
$user->email_verified_at = Carbon::now();
$user->save();
return response()->json([
'status' => true,
'message' => 'email successfully verified',
]);
}
return response()->json([
'status' => false,
'message' => 'Verification code expired',
]);
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace Wave\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = '/dashboard';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $token
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showResetForm(Request $request, $token = null)
{
return view('theme::auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Get the response for a successful password reset.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetResponse(Request $request, $response)
{
if ($request->wantsJson()) {
return new JsonResponse(['message' => trans($response)], 200);
}
return redirect($this->redirectPath())
->with(['message' => 'Welcome back, you have successfully reset your password.', 'message_type' => 'success']);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
use Wave\Category;
use Wave\Post;
class BlogController extends Controller
{
public function index(){
$posts = Post::orderBy('created_at', 'DESC')->paginate(6);
$categories = Category::all();
$seo = [
'seo_title' => 'Blog',
'seo_description' => 'Our Blog',
];
return view('theme::blog.index', compact('posts', 'categories', 'seo'));
}
public function category($slug){
$category = Category::where('slug', '=', $slug)->firstOrFail();
$posts = $category->posts()->orderBy('created_at', 'DESC')->paginate(6);
$categories = Category::all();
$seo = [
'seo_title' => $category->name . '- Blog',
'seo_description' => $category->name . '- Blog',
];
return view('theme::blog.index', compact('posts', 'category', 'categories', 'seo'));
}
public function post($category, $slug){
$post = Post::where('slug', '=', $slug)->firstOrFail();
$category = Category::where('slug', '=', $category)->firstOrFail();
$seo = [
'seo_title' => $post->title,
'seo_description' => $post->seo_description,
];
return view('theme::blog.post', compact('post', 'seo'));
}
}

View File

@@ -0,0 +1,121 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\BookkeepingDocumentCategory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Yajra\DataTables\Facades\DataTables;
class BookkeepingCategoryController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('theme::cms.bookkeepings.categories.index');
}
public function table()
{
$categories = BookkeepingDocumentCategory::query()->select('*');
return Datatables::of($categories)
->escapeColumns(['id'])
->addColumn('status', function ($user) {
$status = $user->status;
if ($status == 'active') {
$status = '<span class="success item-list-note">' . ucwords($status) . '</span>';
}
else if ($status == 'inactive') {
$status = '<span class="failed item-list-note">' . ucwords($status) . '</span>';
}
return $status;
})
->addColumn('actions', function ($category) {
$viewAction = '<a class="primary-text view-edit-category" href="#" data-action-type="view" data-action-show="' . route('cms.bookkeepings.categories.show', $category->id) . '" data-action-update="' . route('cms.bookkeepings.categories.update', $category->id) . '">' . __("View") . '</a>';
$editAction = '<a class="primary-text view-edit-category" href="#" data-action-type="edit" data-action-show="' . route('cms.bookkeepings.categories.show', $category->id) . '" data-action-update="' . route('cms.bookkeepings.categories.update', $category->id) . '">' . __("Edit") . '</a>';
$removeAction = '<a class="failed item-list-note remove-category" href="#" data-action="' . route('cms.bookkeepings.categories.destroy', $category->id) . '">' . __("Archive") . '</a>';
$actions = $viewAction . '<span class="long-pipe">|</span>' . $editAction . '<span class="long-pipe">|</span>' . $removeAction;
return $actions;
})
->make(true);
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255|unique:bookkeeping_document_categories',
'status' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
BookkeepingDocumentCategory::create([
'name' => $request->name,
'status' => $request->status,
]);
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
public function show(BookkeepingDocumentCategory $category)
{
return response()->json([
'success' => true,
'message' => __("Bookkeeping category details has successfully retrieved!"),
'category' => $category,
]);
}
public function update(BookkeepingDocumentCategory $category, Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255|unique:bookkeeping_document_categories,name,' . $category->id,
'status' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$category->update($request->all());
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
public function destroy(BookkeepingDocumentCategory $category)
{
$category->delete();
return response()->json([
'success' => true,
'message' => __("Category has successfully removed!"),
]);
}
}

View File

@@ -0,0 +1,317 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\BookkeepingDocument;
use App\Models\BookkeepingDocumentCategory;
use App\Models\Company;
use App\Models\DocumentActionLogs;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Yajra\DataTables\Facades\DataTables;
class BookkeepingController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('theme::cms.bookkeepings.index');
}
public function getCompanies()
{
$nameColumn = strtolower(app()->getLocale()) == 'zh_hk' ? 'name_chinese' : 'name_english';
$companies = Company::where($nameColumn, '!=', null)
->orderBy($nameColumn)
->get()
->map(function ($company) use ($nameColumn) {
$company->name = $company->{$nameColumn};
return $company;
});
return response()->json([
'success' => true,
'companies' => $companies,
]);
}
public function getCategories()
{
$categories = BookkeepingDocumentCategory::where('status', 'active')
->orderBy('name')
->get();
return response()->json([
'success' => true,
'categories' => $categories,
]);
}
public function table($isCompleted = false)
{
$documents = BookkeepingDocument::query()
->select(
'bookkeeping_documents.id',
'companies.name_english',
'companies.name_chinese',
'bookkeeping_documents.file_name',
'bookkeeping_document_categories.name as category_name',
'users.first_name',
'users.last_name',
'bookkeeping_documents.batch_name',
'bookkeeping_documents.remark',
'bookkeeping_documents.created_at',
'bookkeeping_documents.status',
'bookkeeping_documents.xero_status',
'bookkeeping_documents.xero_amount',
)
->leftJoin('companies', 'bookkeeping_documents.company_id', '=', 'companies.id')
->leftJoin('users', 'bookkeeping_documents.user_id', '=', 'users.id')
->leftJoin('bookkeeping_document_categories', 'bookkeeping_documents.bookkeeping_document_category_id', '=', 'bookkeeping_document_categories.id');
if ($isCompleted) {
$documents = $documents->where('bookkeeping_documents.status', 'completed');
}
else {
$documents = $documents->where('bookkeeping_documents.status', '!=', 'completed');
}
$processCount = $documents->clone()->where('bookkeeping_documents.status', 'in_progress')->count();
$queueCount = $documents->clone()->where('bookkeeping_documents.status', 'uploaded')->count();
return Datatables::of($documents)
->escapeColumns(['id'])
->addColumn('file_name', function ($document) {
$ext = pathinfo($document->file_name, PATHINFO_EXTENSION);
return '
<div class="flex justify-start">
<img class="max-25" src="' . ( $ext == 'pdf' ? asset('themes/tailwind/images/pdf.svg') : asset('themes/tailwind/images/jpg.svg')) . '">
<span class="fix-text">' . $document->file_name . '</span>
</div>
';
})
->addColumn('user_name', function ($document) {
if ($document->status == 'uploaded') {
return '<span class="grey-text">processing...</span>';
}
else if ($document->status == 'failed') {
return '<span class="grey-text" style="color: #6D7581;">Failed</span>';
}
return $document->first_name . ($document->last_name ? ' ' : '') . $document->last_name;
})
->addColumn('created_at', function ($document) {
return date('Ymd-H:i', strtotime($document->created_at));
})
->addColumn('status_select', function ($document) {
$html = '
<select class="change-status" data-id="' . $document->id . '">
<option value="uploaded" ' . ($document->status == 'uploaded' ? 'selected' : '') . '>' . __("Uploaded") . '</option>
<option value="in_progress" ' . ($document->status == 'in_progress' ? 'selected' : '') . '>' . __("In Progress") . '</option>
<option value="ocr_complete" ' . ($document->status == 'ocr_complete' ? 'selected' : '') . '>' . __("OCR Completed") . '</option>
<option value="failed" ' . ($document->status == 'failed' ? 'selected' : '') . '>' . __("Failed") . '</option>
<option value="completed" ' . ($document->status == 'completed' ? 'selected' : '') . '>' . __("Completed") . '</option>
</select>
';
if ($document->status == 'failed') {
$html .= '
<div>
<input type="file" data-id="' . $document->id . '" class="d-none re-upload-file" accept="image/png, image/jpeg, application/pdf, application/msword" multiple>
<button type="button" class="failed item-list-note flex btn-link reupload-button" style="text-wrap: nowrap;">
<img class="max-25" src="' . asset('themes/tailwind/images/flag-2.svg') . '"> ' . __("Reupload") . '
</button>
</div>';
}
else if ($document->status == 'ocr_complete') {
$html .= '<button type="button" class="failed item-list-note flex btn-link" style="text-wrap: nowrap;"><img class="max-25" src="' . asset('themes/tailwind/images/flag-2.svg') . '"> ' . __("Require Datamolino") . '?</button>';
}
return $html;
})
->addColumn('xero_status', function ($document) {
if ($document->status != 'ocr_complete') {
if ($document->xero_status) {
return '<img class="max-25" src="' . asset("themes/tailwind/images/success.svg") . '">';
}
else {
return '<img class="max-25" src="' . asset("themes/tailwind/images/error.svg") . '">';
}
}
return '';
})
->addColumn('xero_amount', function ($document) {
if ($document->xero_amount > 0 && $document->status != 'ocr_complete') {
return '$' . $document->xero_amount;
}
return '';
})
->addColumn('actions', function ($document) {
$actions = '
<div class="dropdown non-custom">
<button type="button" data-bs-toggle="dropdown" aria-expanded="false"><img class="max-25" src="' . asset('themes/tailwind/images/more.svg') . '"></button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">' . __("Cancel Request") . '</a>
<a class="dropdown-item" href="#">' . __("Message on file") . '</a>
<a class="dropdown-item" href="#">' . __("Stop processing") . '</a>
</div>
</div>
';
return $actions;
})
->with([
'processCount' => $processCount,
'queueCount' => $queueCount,
])
->make(true);
}
public function updateStatus(Request $request)
{
$validator = Validator::make($request->all(), [
'id' => 'required',
'status' => 'required',
'xero_status' => [
'nullable',
Rule::requiredIf($request->status == 'completed'),
],
'xero_amount' => [
'nullable',
Rule::requiredIf($request->status == 'completed'),
'numeric',
],
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$bookkeepingDocument = BookkeepingDocument::find($request->id);
if (! $bookkeepingDocument) {
return response()->json([
'success' => false,
'message' => __("Document not exists!"),
]);
}
$bookkeepingDocument->status = $request->status;
if ($request->status == 'completed') {
$bookkeepingDocument->xero_status = $request->xero_status == '1' ? true : false;
$bookkeepingDocument->xero_amount = $request->xero_amount;
}
$bookkeepingDocument->save();
DocumentActionLogs::create([
'user_id' => $request->user()->id,
'event' => 'Change status',
'description' => 'Change [' . $bookkeepingDocument->file_name . '] status to ' . $request->status . '.',
'status' => 'success',
]);
if ($request->status == 'completed') {
storeUserNotification(null, 'Bookkeeping Queue', $bookkeepingDocument->file_name, 'Bookkeeping Queue', true, $bookkeepingDocument->id, 'bookkeeping_queue', 'completed');
}
else if ($request->status == 'failed') {
storeUserNotification(null, 'Bookkeeping Queue', $bookkeepingDocument->file_name, 'Bookkeeping Queue', true, $bookkeepingDocument->id, 'bookkeeping_queue', 'failed');
}
return response()->json([
'success' => true,
'message' => __("Document has successfully updated!"),
]);
}
}
public function actionLogsTable()
{
$logs = DocumentActionLogs::query()
->select(
'users.email',
'users.name',
'document_action_logs.created_at',
'document_action_logs.event',
'document_action_logs.description',
'document_action_logs.status',
)
->leftJoin('users', 'document_action_logs.user_id', '=', 'users.id');
return Datatables::of($logs)
->escapeColumns(['id'])
->addColumn('date', function ($log) {
return date('Ymd', strtotime($log->created_at));
})
->addColumn('time', function ($log) {
return date('H:i', strtotime($log->created_at));
})
->addColumn('status', function ($log) {
return '<span class="' . $log->status . ' item-list-note">' . ucwords($log->status) . '</span>';
})
->make(true);
}
public function reUploadFile(Request $request)
{
$validator = Validator::make($request->all(), [
'id' => 'required',
'uploaded_file' => 'required',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$bookkeepingDocument = BookkeepingDocument::find($request->id);
if (! $bookkeepingDocument) {
return response()->json([
'success' => true,
'message' => __("Document not exists!"),
]);
}
$fileName = '';
if ($request->hasFile('uploaded_file')) {
if (\Storage::exists($bookkeepingDocument->file_path)) {
\Storage::delete($bookkeepingDocument->file_path);
}
$file = $request->file('uploaded_file');
$fileName = $request->file('uploaded_file')->getClientOriginalName();
$file->storePubliclyAs($bookkeepingDocument->folder_path, $fileName);
$bookkeepingDocument->file_name = $fileName;
$bookkeepingDocument->status = 'uploaded';
$bookkeepingDocument->save();
}
DocumentActionLogs::create([
'user_id' => $request->user()->id,
'event' => 'Upload',
'description' => 'Upload [' . $fileName . '] from local file.',
'status' => 'success',
]);
return response()->json([
'success' => true,
'message' => __("Document has successfully uploaded!"),
]);
}
}
}

View File

@@ -0,0 +1,204 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Exports\BookkeepingDocumentLibraryExport;
use App\Models\BookkeepingDocument;
use App\Models\BookkeepingDocumentCategory;
use App\Models\DocumentActionLogs;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Facades\Excel;
use Yajra\DataTables\Facades\DataTables;
use Storage;
class BookkeepingDocumentLibraryController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$categories = BookkeepingDocumentCategory::where('status', 'active')
->orderBy('name')
->get();
return view('theme::cms.bookkeepings.document-libraries.index', [
'categories' => $categories,
]);
}
public function table(Request $request)
{
$documents = BookkeepingDocument::query()
->select(
'bookkeeping_documents.id',
'bookkeeping_documents.file_name',
'companies.name_english',
'companies.name_chinese',
'bookkeeping_document_categories.name as category_name',
'users.name as user_name',
'bookkeeping_documents.created_at',
)
->leftJoin('companies', 'bookkeeping_documents.company_id', '=', 'companies.id')
->leftJoin('users', 'bookkeeping_documents.user_id', '=', 'users.id')
->leftJoin('bookkeeping_document_categories', 'bookkeeping_documents.bookkeeping_document_category_id', '=', 'bookkeeping_document_categories.id')
->when($request->bookkeeping_document_category_id, function ($query) use ($request) {
$query->where('bookkeeping_documents.bookkeeping_document_category_id', $request->bookkeeping_document_category_id);
})
->when($request->status, function ($query) use ($request) {
$query->where('bookkeeping_documents.status', $request->status);
})
->when($request->file_name, function ($query) use ($request) {
$query->where('bookkeeping_documents.file_name', 'like', '%' . $request->file_name . '%');
})
->when($request->date_uploaded, function ($query) use ($request) {
$dateFrom = date('Y-m-d 00:00:00');
$dateTo = date('Y-m-d 23:59:59');
if ($request->date_uploaded == 'yesterday') {
$dateFrom = date('Y-m-d 00:00:00', strtotime('-1 days'));
$dateTo = date('Y-m-d 23:59:59', strtotime('-1 days'));
} else if ($request->date_uploaded == 'last_7_days') {
$dateFrom = date('Y-m-d 00:00:00', strtotime('-7 days'));
$dateTo = date('Y-m-d 23:59:59');
} else if ($request->date_uploaded == 'last_30_days') {
$dateFrom = date('Y-m-d 00:00:00', strtotime('-30 days'));
$dateTo = date('Y-m-d 23:59:59');
} else if ($request->date_uploaded == 'last_90_days') {
$dateFrom = date('Y-m-d 00:00:00', strtotime('-90 days'));
$dateTo = date('Y-m-d 23:59:59');
} else if ($request->date_uploaded == 'custom') {
$dateFrom = date('Y-m-d 00:00:00', strtotime($request->date_uploaded_from));
$dateTo = date('Y-m-d 23:59:59', strtotime($request->date_uploaded_to));
}
$query->where('bookkeeping_documents.created_at', '>=', $dateFrom);
$query->where('bookkeeping_documents.created_at', '<=', $dateTo);
});
return Datatables::of($documents)
->escapeColumns(['id'])
// ->addColumn('checkbox', function ($document) {
// return '<input type="checkbox">';
// })
->addColumn('file_name', function ($document) {
$ext = pathinfo($document->file_name, PATHINFO_EXTENSION);
return '
<div class="flex justify-start">
<img class="max-25" src="' . ( $ext == 'pdf' ? asset('themes/tailwind/images/pdf.svg') : asset('themes/tailwind/images/jpg.svg')) . '">
<span class="fix-text">' . $document->file_name . '</span>
</div>
';
})
->addColumn('document_size', function ($document) {
if (Storage::exists($document->file_path)) {
return '<span class="primary-text">' . round(Storage::size($document->file_path) / 1000) . 'KB</span>';
}
return '-';
})
->addColumn('created_at', function ($document) {
return date('Ymd-H:i', strtotime($document->created_at));
})
->addColumn('actions', function ($document) {
$viewAction = '<a class="primary-text" href="#">' . __("View") . '</a>';
$propertiesAction = '<a class="primary-text" href="#">' . __("Properties") . '</a>';
$downloadAction = '<a class="primary-text download-file" data-id="' . $document->id . '" href="' . $document->file_url . '" download>' . __("Download") . '</a>';
$actions = $viewAction . '<span class="long-pipe">|</span>' . $propertiesAction . '<span class="long-pipe">|</span>' . $downloadAction;
return $actions;
})
->make(true);
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'company_id' => 'required',
'uploaded_file' => 'required',
'bookkeeping_document_category_id' => 'required',
'batch_name' => 'required',
'remark' => 'required',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$bookkeepingDocument = BookkeepingDocument::create([
'company_id' => $request->company_id,
'user_id' => $request->user()->id,
'batch_name' => $request->batch_name,
'remark' => $request->remark,
'bookkeeping_document_category_id' => $request->bookkeeping_document_category_id,
]);
$fileName = '';
if ($request->hasFile('uploaded_file')) {
$file = $request->file('uploaded_file');
$fileName = $request->file('uploaded_file')->getClientOriginalName();
$file->storePubliclyAs($bookkeepingDocument->folder_path, $fileName);
$bookkeepingDocument->file_name = $fileName;
$bookkeepingDocument->save();
}
DocumentActionLogs::create([
'user_id' => $request->user()->id,
'event' => 'Upload',
'description' => 'Upload [' . $fileName . '] from local file.',
'status' => 'success',
]);
return response()->json([
'success' => true,
'message' => __("Document has successfully uploaded!"),
]);
}
}
public function export()
{
$documents = BookkeepingDocument::query()
->select(
'bookkeeping_documents.id',
'bookkeeping_documents.file_name',
'companies.name_english',
'companies.name_chinese',
'bookkeeping_document_categories.name as category_name',
'users.name as user_name',
'bookkeeping_documents.created_at',
)
->leftJoin('companies', 'bookkeeping_documents.company_id', '=', 'companies.id')
->leftJoin('users', 'bookkeeping_documents.user_id', '=', 'users.id')
->leftJoin('bookkeeping_document_categories', 'bookkeeping_documents.bookkeeping_document_category_id', '=', 'bookkeeping_document_categories.id')
->get();
$fileName = 'bookkeeping-documents-' . date('mdY') . '.xls';
return Excel::download(new BookkeepingDocumentLibraryExport($documents), $fileName, \Maatwebsite\Excel\Excel::XLS);
}
public function download(BookkeepingDocument $document)
{
DocumentActionLogs::create([
'user_id' => auth()->user()->id,
'event' => 'Download',
'description' => 'Download [' . $document->file_name . '] to local.',
'status' => 'success',
]);
return response()->json([
'success' => true,
]);
}
}

View File

@@ -0,0 +1,170 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Events\ChatEvent;
use App\Http\Controllers\Controller;
use App\Models\ServiceChat;
use App\Models\ServiceChatMessage;
use App\Models\User;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ChatController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application cms dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return view('theme::cms.chats.index');
}
public function getChats(Request $request)
{
$chats = ServiceChat::latest()
->select('service_chats.*')
->leftJoin('users', 'service_chats.user_id', '=', 'users.id')
->whereNull('users.deleted_at')
->get()
->groupBy('user_id', 'company_id')
->map(static function ($chat) {
$unreadCount = 0;
$chat->map(static function ($item) use (&$unreadCount) {
$unreadCount += $item->messages->where('to_admin', true)->where('is_read', false)->count();
});
$chat = $chat->first();
$chat->unread_count = $unreadCount;
$chat->user_id = $chat->user->id;
$chat->user_first_name = $chat->user->first_name;
$chat->user_last_name = $chat->user->last_name;
$chat->company_id = $chat->company->id;
$chat->company_name = $chat->company->name;
unset($chat->user);
unset($chat->company);
return $chat;
})
->values()
->all();
return response()->json([
'success' => true,
'chats' => $chats,
]);
}
public function getTopics(Request $request)
{
$chats = ServiceChat::latest()
->select('service_chats.*')
->leftJoin('users', 'service_chats.user_id', '=', 'users.id')
->whereNull('users.deleted_at')
->where('service_chats.user_id', $request->userId)
->where('service_chats.company_id', $request->companyId)
->get()
->map(static function ($chat) {
$chat->topic = $chat->service_type == 'bookkeeping' ? __("Bookkeeping Service") : __("Company Secretary Service");
$chat->date = $chat->created_at->format('d/m/Y');
$chat->first_message = $chat->messages->count() ? $chat->messages->first()->message : '';
$chat->unread_count = $chat->messages->where('to_admin', true)->where('is_read', false)->count();
unset($chat->messages);
return $chat;
});
$user = User::find($request->userId);
$company = Company::find($request->companyId);
$company->adderss = $company->address;
return response()->json([
'success' => true,
'chats' => $chats,
'user' => $user,
'company' => $company,
]);
}
public function getMessages(ServiceChat $serviceChat)
{
$newCollection = collect();
$messages = $serviceChat ? $serviceChat->messages : null;
if ($messages) {
$newCollection = $messages->map(function ($message) use ($serviceChat) {
$message->date = $message->created_at->format('Y-m-d');
$message->is_own_message = request()->user()->id == $message->from_user_id ? true : false;
$message->elapsed_time = $message->elapsed_time;
$message->is_today = $message->created_at->format('Y-m-d') == date('Y-m-d') ? true : false;
$message->message = $message->is_file ? '<a href="' . $message->file_url . '" target="_blank">' . $message->file_name . '</a>' : $message->message;
$userFirstName = $serviceChat->user->first_name ? ucfirst($serviceChat->user->first_name) : '';
$userLastName = $serviceChat->user->last_name ? ucfirst($serviceChat->user->last_name) : '';
$userInitial = ($userFirstName ? $userFirstName[0] : '') . ($userLastName ? $userLastName[0] : '');
$message->initials = $message->is_own_message ? 'CS' : ($userInitial ? $userInitial : '-');
return $message;
})
->groupBy('date')
->map(function ($message) {
return $message->flatmap(function ($item) use ($message) {
return [
'date' => $item->created_at->format('d F, Y'),
'is_today' => $item->is_today,
'messages' => $message,
];
});
})
->values()
->all();
ServiceChatMessage::whereIn('id', $messages->pluck('id')->toArray())
->where('to_admin', true)
->update(['is_read' => true]);
}
return response()->json([
'success' => true,
'data' => $newCollection,
]);
}
public function sendMessage(ServiceChat $serviceChat, Request $request)
{
$messageFileName = '';
if ($request->hasFile('chat_message_file')) {
$file = $request->file('chat_message_file');
$messageFileName = $request->file('chat_message_file')->getClientOriginalName();
$file->storePubliclyAs($serviceChat->folder_path, $messageFileName);
}
ServiceChatMessage::create([
'service_chat_id' => $serviceChat->id,
'message' => $request->chat_message,
'from_user_id' => $request->user()->id,
'to_user_id' => $serviceChat->user_id,
'is_file' => $messageFileName ? true : false,
'file_name' => $messageFileName,
]);
ChatEvent::dispatch($serviceChat->id, false, $serviceChat->user_id);
return response()->json([
'success' => true,
]);
}
}

View File

@@ -0,0 +1,233 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Mail\SendUserInvite;
use App\Models\Company;
use App\Models\InviteUser;
use App\Models\User;
use App\Models\UserAccessLog;
use App\Models\Role;
use App\Models\CompanySubscription;
use Illuminate\Http\Request;
use Yajra\DataTables\Facades\DataTables;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
class CompanyController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('theme::cms.companies.index');
}
public function table(Request $request)
{
$companies = Company::query()
->select(
'companies.id',
'companies.name_english',
'companies.name_chinese',
)
->when($request->company_name, function ($query) use ($request) {
$query->where(function($query2) use ($request){
$query2->orWhere('companies.name_english', 'like', '%' . $request->company_name . '%');
$query2->orWhere('companies.name_chinese', 'like', '%' . $request->company_name . '%');
});
});
return Datatables::of($companies)
->escapeColumns(['id'])
->addColumn('bookkeeping_subscription', function ($company) { // Temporary
return '
<span class="success item-list-note d-block">Active</span>
<span class="item-list-note d-block">' . __("Expiration") . ': 2024/05/16</span>
';
})
->addColumn('bookkeeping_requests_count', function ($company) { // Temporary
return '0';
})
->addColumn('com_sec_subscription', function ($company) { // Temporary
return '
<span class="failed item-list-note d-block">Expired</span>
<span class="item-list-note d-block">' . __("Expiration") . ': 2023/04/16</span>
';
})
->addColumn('com_sec_requests_count', function ($company) { // Temporary
return '0';
})
->addColumn('actions', function ($company) {
$viewAction = '<a href="' . route('cms.companies.show', $company->id) . '" class="primary-text">' . __("View") . '</a>';
$editAction = '<a href="' . route('cms.companies.show', $company->id) . '" class="primary-text">' . __("Edit") . '</a>';
$actions = $viewAction . '<span class="long-pipe">|</span>' . $editAction;
return $actions;
})
->make(true);
}
public function show(Company $company)
{
$roles = Role::whereIn('id', [
Role::OWNER_ROLE,
Role::ADMINISTRATOR_ROLE,
Role::BOOKKEEPER_ROLE,
Role::COMPANY_SECRETARY_ROLE,
])->get();
$company_subscription = CompanySubscription::with('subscription')->where('company_id', $company->id)->get();
return view('theme::cms.companies.show')->with([
'company' => $company,
'roles' => $roles,
'company_subscription' => $company_subscription,
]);
}
public function usersTable(Company $company)
{
$users = User::query()
->select(
'users.id',
'users.first_name',
'users.last_name',
'users.phone',
'users.email',
'roles.display_name',
'users.status',
)
->leftJoin('roles', 'users.role_id', '=', 'roles.id')
->where('users.company_id', $company->id);
return Datatables::of($users)
->escapeColumns(['id'])
->addColumn('status', function ($user) {
$status = $user->status;
if ($status == 'active') {
$status = '<span class="success item-list-note">' . ucwords($status) . '</span>';
}
else if ($status == 'inactive') {
$status = '<span class="failed item-list-note">' . ucwords($status) . '</span>';
}
return $status;
})
->addColumn('actions', function ($user) {
$suspendAction = '<a class="dropdown-item suspend-user" href="#" data-action="' . route('cms.users.suspend', $user->id) . '">' . __("Suspend user") . '</a>';
$activateAction = '<a class="dropdown-item activate-user" href="#" data-action="' . route('cms.users.activate', $user->id) . '">' . __("Activate user") . '</a>';
$removeAction = '<a class="dropdown-item remove-user" href="#" data-action="' . route('cms.users.destroy', $user->id) . '">' . __("Remove user") . '</a>';
$viewUserLogAction = '<a class="dropdown-item view-user-log" data-action="' . route("cms.users.accessLogsTable", $user->id) . '" href="#">' . __("View user log") . '</a>';
$editUserAction = '<a class="dropdown-item edit-user" href="#" data-action-show="' . route('cms.users.show', $user->id) . '" data-action-update="' . route('cms.users.update', $user->id) . '">' . __("Edit user") . '</a>';
$actions = '
<div class="dropdown non-custom">
<button type="button" data-bs-toggle="dropdown" aria-expanded="false"><img class="max-25" src="' . asset('themes/tailwind/images/more.svg') . '"></button>
<div class="dropdown-menu">
' . ($user->status == 'active' ? $suspendAction : $activateAction) . '
' . $removeAction . '
' . $viewUserLogAction . '
' . $editUserAction . '
</div>
</div>
';
return $actions;
})
->make(true);
}
public function accessLogsTable(Company $company)
{
$logs = UserAccessLog::query()
->select(
'users.email',
'user_access_logs.created_at',
'user_access_logs.event',
'user_access_logs.description',
'user_access_logs.status',
)
->leftJoin('users', 'user_access_logs.user_id', '=', 'users.id')
->where('users.company_id', $company->id);
return Datatables::of($logs)
->escapeColumns(['id'])
->addColumn('date', function ($log) {
return date('Ymd', strtotime($log->created_at));
})
->addColumn('time', function ($log) {
return date('H:i', strtotime($log->created_at));
})
->addColumn('status', function ($log) {
return '<span class="' . $log->status . ' item-list-note">' . ucwords($log->status) . '</span>';
})
->make(true);
}
public function updateXeroApi(Company $company, Request $request)
{
$validator = Validator::make($request->all(), [
'xero_api_key' => 'required|string|max:255',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$company->update([
'xero_api_key' => $request->xero_api_key,
]);
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
public function sendUserInvite(Company $company, Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255|unique:users',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$token = '';
while (true) {
$token = str()->random(20);
$tokenExists = InviteUser::where('token', $token)->first();
if (!$tokenExists) {
break;
}
}
InviteUser::create([
'email' => $request->email,
'token' => $token,
'user_id' => $request->user()->id,
'company_id' => $company->id,
'is_used' => false,
]);
$url = route('register', ['token' => $token]);
Mail::to($request->email)->send(new SendUserInvite($url, $company->name));
return response()->json([
'success' => true,
'message' => __("Invitation sent!"),
]);
}
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Role;
use Illuminate\Http\Request;
use Yajra\DataTables\Facades\DataTables;
class CrmController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index(){
$roles = Role::whereIn('id', [
Role::OWNER_ROLE,
Role::ADMINISTRATOR_ROLE,
Role::BOOKKEEPER_ROLE,
Role::COMPANY_SECRETARY_ROLE,
])->get();
return view('theme::cms.crm.index')->with([
'roles' => $roles,
]);
}
public function table(Request $request){
$users = User::query()
->select(
'users.id',
'companies.id as company_id',
'companies.name_english',
'companies.name_chinese',
'users.first_name',
'users.last_name',
'users.phone',
'users.email',
'roles.display_name',
'users.status',
)
->leftJoin('roles', 'users.role_id', '=', 'roles.id')
->leftJoin('companies', 'users.company_id', '=', 'companies.id')
->whereIn('users.role_id', [
Role::OWNER_ROLE,
Role::ADMINISTRATOR_ROLE,
Role::BOOKKEEPER_ROLE,
Role::COMPANY_SECRETARY_ROLE,
])
->when($request->company_name, function ($query) use ($request) {
$query->where(function($query2) use ($request){
$query2->orWhere('companies.name_english', 'like', '%' . $request->company_name . '%');
$query2->orWhere('companies.name_chinese', 'like', '%' . $request->company_name . '%');
});
})
->when($request->first_name, function ($query) use ($request) {
$query->where('users.first_name', 'like', '%' . $request->first_name . '%');
})
->when($request->last_name, function ($query) use ($request) {
$query->where('users.last_name', 'like', '%' . $request->last_name . '%');
})
->when($request->phone, function ($query) use ($request) {
$query->where('users.phone', 'like', '%' . $request->phone . '%');
});
return Datatables::of($users)
->escapeColumns(['id'])
->addColumn('status', function ($user) {
$status = $user->status;
if ($status == 'active') {
$status = '<span class="success item-list-note">' . ucwords($status) . '</span>';
}
else if ($status == 'inactive') {
$status = '<span class="failed item-list-note">' . ucwords($status) . '</span>';
}
return $status;
})
->addColumn('actions', function ($user) {
$suspendAction = '';
$activateAction = '';
$removeAction = '';
$editUserAction = '';
if (auth()->user()->userRole->hasAccess('manage-crm')) {
$suspendAction = '<a class="dropdown-item suspend-user" href="#" data-action="' . route('cms.users.suspend', $user->id) . '">' . __("Suspend user") . '</a>';
$activateAction = '<a class="dropdown-item activate-user" href="#" data-action="' . route('cms.users.activate', $user->id) . '">' . __("Activate user") . '</a>';
$removeAction = '<a class="dropdown-item remove-user" href="#" data-action="' . route('cms.users.destroy', $user->id) . '">' . __("Remove user") . '</a>';
$editUserAction = '<a class="dropdown-item edit-user" href="#" data-action-show="' . route('cms.users.show', $user->id) . '" data-action-update="' . route('cms.users.update', $user->id) . '">' . __("Edit user") . '</a>';
}
$viewUserLogAction = '<a class="dropdown-item view-user-log" data-action="' . route("cms.users.accessLogsTable", $user->id) . '" href="#">' . __("View user log") . '</a>';
$actions = '
<div class="dropdown non-custom">
<button type="button" data-bs-toggle="dropdown" aria-expanded="false"><img class="max-25" src="' . asset('themes/tailwind/images/more.svg') . '"></button>
<div class="dropdown-menu">
' . ($user->status == 'active' ? $suspendAction : $activateAction) . '
' . $removeAction . '
' . $viewUserLogAction . '
' . $editUserAction . '
</div>
</div>
';
return $actions;
})
->make(true);
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\UserNotification;
class DashboardController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application cms dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return view('theme::cms.index');
}
public function bookkeeping()
{
return view('theme::cms.bookkeeping');
}
public function company_secretary()
{
return view('theme::cms.company-secretary');
}
public function getNotifications()
{
$offset = request('offset') ? request('offset') : 0;
$limit = request('limit') ? request('limit') : 5;
$hasNew = UserNotification::where('is_admin', true)->where('is_read', false)->exists();
$notifications = UserNotification::where('is_admin', true)
->latest()
->offset($offset)
->limit($limit)
->get()
->map(function ($item) {
$item->category_url = $item->category_url;
$item->url = $item->url;
$item->image_url = $item->image_url;
return $item;
});
UserNotification::where('is_admin', true)
->latest()
->offset($offset)
->limit($limit)
->update(['is_read' => true]);
return response()->json([
'status' => true,
'notifications' => $notifications,
'has_new' => $hasNew,
]);
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\UserEnquiry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class EnquiryController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$companySecretaryEnquiries = UserEnquiry::where('category', 'company_secretary')->get();
$generalEnquiries = UserEnquiry::where('category', 'general')->get();
return view('theme::cms.enquiries.index', [
'companySecretaryEnquiries' => $companySecretaryEnquiries,
'generalEnquiries' => $generalEnquiries,
]);
}
public function show(UserEnquiry $enquiry)
{
$enquiry->company_name = isset($enquiry->user->company->name) ? $enquiry->user->company->name : '-';
$enquiry->submitted_date = $enquiry->created_at->format('d/m/Y H:i');
return response()->json([
'success' => true,
'message' => '',
'enquiry' => $enquiry,
]);
}
public function updateReply(UserEnquiry $enquiry, Request $request)
{
$validator = Validator::make($request->all(), [
'reply' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => __('Fill up all required fields!')
], 200);
}
else {
$enquiry->reply = $request->reply;
$enquiry->save();
return response()->json([
'success' => true,
'message' => __("Reply have been saved!"),
]);
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PrivacyPolicyController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::cms.privacy-policy.index', [
'siteSetting' => $siteSetting,
]);
}
public function update(Request $request)
{
$validator = Validator::make($request->all(), [
'privacy_policy_english' => 'required',
'privacy_policy_chinese' => 'required',
]);
if ($validator->fails()) {
return redirect()->back()->with(['message' => __('Fill up all required fields!'), 'message_type' => 'danger', 'show_toast' => true]);
}
else {
$siteSetting = SiteSetting::latest()->first();
if ($siteSetting) {
$siteSetting->update($request->all());
}
else {
SiteSetting::create($request->all());
}
return redirect()->back()->with(['message' => __('Privacy policy has successfully updated!'), 'message_type' => 'success', 'show_toast' => true]);
}
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\PermissionGroup;
use App\Models\PermissionRole;
use App\Models\Role;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Yajra\DataTables\Facades\DataTables;
class SecurityController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application cms dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$roles = Role::whereIn('id', [
Role::IT_PERSONNEL_ROLE,
Role::NUMSTATION_MANAGER_ROLE,
Role::NUMSTATION_STAFF_ROLE,
])->get();
$permissionGroups = PermissionGroup::where('platform', 'admin')->get();
return view('theme::cms.securities.index', [
'roles' => $roles,
'permissionGroups' => $permissionGroups,
]);
}
public function groupListTable()
{
$roles = Role::query()
->select('*')
->whereIn('id', [
Role::IT_PERSONNEL_ROLE,
Role::NUMSTATION_MANAGER_ROLE,
Role::NUMSTATION_STAFF_ROLE,
]);
return Datatables::of($roles)
->escapeColumns(['id'])
->addColumn('status', function ($role) {
$status = $role->status;
if ($status == 'active') {
$status = '<span class="success item-list-note">' . ucwords($status) . '</span>';
}
else if ($status == 'inactive') {
$status = '<span class="failed item-list-note">' . ucwords($status) . '</span>';
}
return $status;
})
->addColumn('actions', function ($role) {
if (auth()->user()->userRole->hasAccess('manage-security-group')) {
$suspendAction = '<a class="failed item-list-note suspend-role" href="#" data-action="' . route('cms.securities.suspend', $role->id) . '">' . __("Suspend") . '</a>';
$activateAction = '<a class="primary-text activate-role" href="#" data-action="' . route('cms.securities.activate', $role->id) . '">' . __("Activate") . '</a>';
$viewAction = '<a href="#" class="primary-text view-edit-action" data-type="view">' . __("View") . '</a>';
$editAction = '<a href="#" class="primary-text view-edit-action" data-type="edit">' . __("Edit") . '</a>';
$actions = $viewAction . '<span class="long-pipe">|</span>' . $editAction . '<span class="long-pipe">|</span>' . ($role->status == 'active' ? $suspendAction : $activateAction);
return $actions;
}
return '';
})
->make(true);
}
public function suspend(Role $role)
{
$role->status = 'inactive';
$role->save();
$role->users()->update([
'status' => 'inactive',
]);
return response()->json([
'success' => true,
'message' => __("Role has successfully suspended!"),
]);
}
public function activate(Role $role)
{
$role->status = 'active';
$role->save();
return response()->json([
'success' => true,
'message' => __("Role has successfully activated!"),
]);
}
public function updateRolePermission(Request $request)
{
$validator = Validator::make($request->all(), [
'role_permissions' => 'required|array',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
$permissionsGroup = $request->role_permissions ? collect($request->role_permissions) : collect();
$permissionsGroup = $permissionsGroup->map(function ($item) {
$permissionArr = explode('-', $item);
return collect([
'role_id' => $permissionArr[0],
'permission_id' => $permissionArr[1],
]);
})->groupBy(static function ($item) {
return $item['role_id'];
})->map(function ($permission) {
return $permission->flatMap(static function ($item) use ($permission) {
return [
'role_id' => $item['role_id'],
'role_permissions' => $permission->toArray(),
];
});
});
foreach ($permissionsGroup as $permission) {
$rolePermissions = [];
$role = Role::find($permission['role_id']);
if ($role) {
$role->rolePermissions()->delete();
foreach ($permission['role_permissions'] as $rolePermission) {
$rolePermissions[] = new PermissionRole($rolePermission);
}
$role->rolePermissions()->saveMany($rolePermissions);
}
}
return response()->json([
'success' => true,
'message' => __("Role permissions has successfully updated!"),
]);
}
}

View File

@@ -0,0 +1,244 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\OnlineHelp;
use App\Models\SiteSetting;
use App\Models\User;
use App\Models\UserNotificationSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Yajra\DataTables\Facades\DataTables;
class SettingController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::cms.settings.index', [
'siteSetting' => $siteSetting,
]);
}
public function updateContactUs(Request $request)
{
$validator = Validator::make($request->all(), [
'phone' => 'required|string',
'whatsapp' => 'required|string',
'email' => 'required|string|email',
'office_hour_english' => 'required|string',
'office_hour_chinese' => 'required|string',
'address_english' => 'required|string',
'address_chinese' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => __('Fill up all required fields!')
], 200);
}
else {
$siteSetting = SiteSetting::latest()->first();
if ($siteSetting) {
$siteSetting->update($request->all());
}
else {
SiteSetting::create($request->all());
}
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
public function updatePassword(Request $request)
{
$validator = Validator::make($request->all(), [
'current_password' => ['required', 'string', 'min:6', function ($attribute, $value, $fail) use ($request) {
if (!\Hash::check($value, $request->user()->password)) {
return $fail(__('The current password is incorrect.'));
}
}],
'new_password' => 'required|string|min:6|confirmed',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => $validator->errors()->first(),
], 200);
}
else {
$user = User::find($request->user()->id);
if ($user) {
$user->password = bcrypt($request->new_password);
$user->save();
}
return response()->json([
'success' => true,
'message' => __("Password has successfully saved!"),
]);
}
}
public function tableOnlineHelp(Request $request)
{
$onlineHelps = OnlineHelp::query()
->select(
'id',
'category',
'sort',
'title_english',
'title_chinese',
'details_english',
'details_chinese',
);
return Datatables::of($onlineHelps)
->escapeColumns(['id'])
->addColumn('category_name_display', function ($onlineHelp) { // Temporary
return $onlineHelp->category_name_display;
})
->addColumn('actions', function ($onlineHelp) {
$viewAction = '<a href="#" class="primary-text show-online-help-frm" data-fields="' . htmlspecialchars(json_encode($onlineHelp->toArray())) . '" data-frm-type="view" data-id="' . $onlineHelp->id . '">' . __("View") . '</a>';
$editAction = '<a href="#" class="primary-text show-online-help-frm" data-fields="' . htmlspecialchars(json_encode($onlineHelp->toArray())) . '" data-frm-type="edit" data-id="' . $onlineHelp->id . '">' . __("Edit") . '</a>';
$removeAction = '<a href="#" class="item-list-note failed delete-online-help" data-action="' . route('cms.settings.destroy-online-help', $onlineHelp->id) . '">' . __("Delete") . '</a>';
$actions = $viewAction . '<span class="long-pipe mx-2">|</span>' . $editAction . '<span class="long-pipe mx-2">|</span>' . $removeAction;
return $actions;
})
->make(true);
}
public function storeOnlineHelp(Request $request)
{
$validator = Validator::make($request->all(), [
'category' => 'required|string',
'title_english' => 'required|string|max:255',
'title_chinese' => 'required|string|max:255',
'details_english' => 'required|string',
'details_chinese' => 'required|string',
'sort' => 'required|integer|min:1',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$onlineHelpSortExists = OnlineHelp::where('category', $request->category)->where('sort', $request->sort)->first();
if ($onlineHelpSortExists) {
return response()->json([
'success' => false,
'message' => __("Sort value already exists!"),
]);
}
OnlineHelp::create($request->all());
return response()->json([
'success' => true,
'message' => __("Online Help has successfully saved!"),
]);
}
}
public function updateOnlineHelp(OnlineHelp $onlineHelp, Request $request)
{
$validator = Validator::make($request->all(), [
'category' => 'required|string',
'title_english' => 'required|string|max:255',
'title_chinese' => 'required|string|max:255',
'details_english' => 'required|string',
'details_chinese' => 'required|string',
'sort' => 'required|integer|min:1',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$onlineHelp->update($request->all());
return response()->json([
'success' => true,
'message' => __("Online Help has successfully saved!"),
]);
}
}
public function destroyOnlineHelp(OnlineHelp $onlineHelp)
{
$onlineHelp->delete();
return response()->json([
'success' => true,
'message' => __("Online Help has successfully removed!"),
]);
}
public function updateNotificationSettings(Request $request)
{
UserNotificationSetting::where('user_id', $request->user()->id)->update(['is_active' => false]);
if (isset($request->notifications) && count($request->notifications) > 0) {
foreach ($request->notifications as $notification) {
$userNotificationSetting = UserNotificationSetting::updateOrCreate(
[
'user_id' => $request->user()->id,
'notification' => $notification,
],
[
'is_active' => true,
],
);
}
}
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
public function updateApiKey(Request $request)
{
$validator = Validator::make($request->all(), [
'google_drive_api_key' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => __('Fill up all required fields!')
], 200);
}
else {
$siteSetting = SiteSetting::latest()->first();
if ($siteSetting) {
$siteSetting->update($request->all());
}
else {
SiteSetting::create($request->all());
}
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\CompanySubscription;
use App\Models\Subscription;
use Illuminate\Http\Request;
use Yajra\DataTables\Facades\DataTables;
class SubscriptionController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('theme::cms.subscriptions.index');
}
public function table(Request $request, $status = 'active')
{
$companySubscriptions = CompanySubscription::query()
->leftJoin('companies', 'company_subscriptions.company_id', '=', 'companies.id')
->leftJoin('subscriptions', 'company_subscriptions.subscription_id', '=', 'subscriptions.id')
->select(
'company_subscriptions.id',
'companies.name_english as company_name_english',
'companies.name_chinese as company_name_chinese',
'company_subscriptions.created_at',
'subscriptions.service_type',
'company_subscriptions.expiration_at',
'subscriptions.name_english',
'subscriptions.name_chinese',
'company_subscriptions.status',
)
->when($request->company_name, function ($query) use ($request) {
$query->where(function($query2) use ($request){
$query2->orWhere('companies.name_english', 'like', '%' . $request->company_name . '%');
$query2->orWhere('companies.name_chinese', 'like', '%' . $request->company_name . '%');
});
})
->when($request->service_type, function ($query) use ($request) {
$query->where('subscriptions.service_type', $request->service_type);
})
->when($request->subscription_id, function ($query) use ($request) {
$query->where('subscriptions.id', $request->subscription_id);
});
if ($status == 'active') {
$companySubscriptions = $companySubscriptions->where('company_subscriptions.status', true);
}
else if ($status == 'expired') {
$companySubscriptions = $companySubscriptions->where('company_subscriptions.status', false);
}
return Datatables::of($companySubscriptions)
->escapeColumns(['id'])
->addColumn('service_type', function ($companySubscription) {
if ($companySubscription->service_type == 'bookkeeping') {
return __('Bookkeeping');
}
else if ($companySubscription->service_type == 'company_secretary') {
return __('Company Secretary');
}
else if ($companySubscription->service_type == 'incorporation') {
return __('Incorporation');
}
})
->addColumn('subscription_period', function ($companySubscription) {
if ($companySubscription->expiration_at) {
return date('Y.m.d', strtotime($companySubscription->created_at)) . '-' . date('Y.m.d', strtotime($companySubscription->expiration_at));
}
return '-';
})
->addColumn('created_at', function ($companySubscription) {
return date('Ymd', strtotime($companySubscription->created_at));
})
->addColumn('status', function ($companySubscription) {
return '<span class="success item-list-note">Active</span>';
})
->addColumn('invoice', function ($company) { // Temporary
return '<a href=""><img class="max-25" src="' . asset('themes/tailwind/images/download.svg') . '"></a>';
})
->make(true);
}
public function getSubscriptions($service_type)
{
$subscriptions = Subscription::where('service_type', $service_type);
if (strtolower(app()->getLocale()) == 'zh_hk') {
$subscriptions->orderBy('name_chinese');
}
else {
$subscriptions->orderBy('name_english');
}
return response()->json([
'success' => true,
'subscriptions' => $subscriptions->get(),
]);
}
}

View File

@@ -0,0 +1,251 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\Subscription;
use App\Models\SubscriptionBasicService;
use App\Models\SubscriptionBasicServiceList;
use App\Models\SubscriptionOptionalService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Yajra\DataTables\Facades\DataTables;
class SubscriptionManagementController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('theme::cms.subscriptions.management.index');
}
public function table($service_type)
{
$subscriptions = Subscription::where('service_type', $service_type);
return Datatables::of($subscriptions)
->escapeColumns(['id'])
->addColumn('price', function ($subscription) {
$price = '$' . number_format($subscription->price);
return $price;
})
->addColumn('period_english', function ($subscription) {
return ucfirst($subscription->period_english);
})
->addColumn('status', function ($subscription) {
$status = $subscription->status;
if ($status == 'active') {
$status = '<span class="success item-list-note">' . ucwords($status) . '</span>';
}
else if ($status == 'inactive') {
$status = '<span class="failed item-list-note">' . ucwords($status) . '</span>';
}
return $status;
})
->addColumn('actions', function ($subscription) {
if (auth()->user()->userRole->hasAccess('manage-subscription-packages')) {
$suspendAction = '<a class="failed item-list-note suspend-subscription" href="#" data-action="' . route('cms.subscriptions.management.suspend', $subscription->id) . '">' . __("Suspend") . '</a>';
$activateAction = '<a class="primary-text activate-subscription" href="#" data-action="' . route('cms.subscriptions.management.activate', $subscription->id) . '">' . __("Activate") . '</a>';
$viewAction = '<a href="' . route('cms.subscriptions.management.edit', $subscription->id) . '" class="primary-text">' . __("View") . '</a>';
$editAction = '<a href="' . route('cms.subscriptions.management.edit', $subscription->id) . '" class="primary-text">' . __("Edit") . '</a>';
$actions = $viewAction . '<span class="long-pipe">|</span>' . $editAction . '<span class="long-pipe">|</span>' . ($subscription->status == 'active' ? $suspendAction : $activateAction);
return $actions;
}
return '';
})
->make(true);
}
public function suspend(Subscription $subscription)
{
$subscription->status = 'inactive';
$subscription->save();
return response()->json([
'success' => true,
'message' => __("Subscription has successfully suspended!"),
]);
}
public function activate(Subscription $subscription)
{
$subscription->status = 'active';
$subscription->save();
return response()->json([
'success' => true,
'message' => __("Subscription has successfully activated!"),
]);
}
public function create($serviceType)
{
return view('theme::cms.subscriptions.management.create', [
'service_type' => $serviceType,
]);
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'service_type' => 'required|string',
'status' => 'required|in:active,inactive',
'name_english' => 'required|string',
'name_chinese' => 'required|string',
'period_english' => 'required|in:annually,monthly,daily',
'period_chinese' => 'required|in:每年,每月,每日',
'description_english' => 'required|string',
'description_chinese' => 'required|string',
'price' => 'required|numeric',
'basic_service_title_english' => 'required|array',
'basic_service_title_chinese' => 'required|array',
'basic_service_list_title_english' => 'required|array',
'basic_service_list_title_chinese' => 'required|array',
'optional_service_title_english' => 'required|array',
'optional_service_title_chinese' => 'required|array',
'optional_service_is_custom' => 'required|array',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$subscription = Subscription::create([
'service_type' => $request->service_type,
'name_english' => $request->name_english,
'name_chinese' => $request->name_chinese,
'period_english' => $request->period_english,
'period_chinese' => $request->period_chinese,
'description_english' => $request->description_english,
'description_chinese' => $request->description_chinese,
'price' => $request->price,
'status' => $request->status,
]);
foreach ($request->basic_service_title_english as $key => $basic_service_title_english) {
$subscriptionBasicService = SubscriptionBasicService::create([
'subscription_id' => $subscription->id,
'title_english' => $request->basic_service_title_english[$key],
'title_chinese' => $request->basic_service_title_chinese[$key],
]);
foreach ($request->basic_service_list_title_english[$key] as $key2 => $basic_service_list_title_english) {
SubscriptionBasicServiceList::create([
'subscription_basic_service_id' => $subscriptionBasicService->id,
'title_english' => $request->basic_service_list_title_english[$key][$key2],
'title_chinese' => $request->basic_service_list_title_chinese[$key][$key2],
]);
}
}
foreach ($request->optional_service_title_english as $key => $optional_service_title_english) {
SubscriptionOptionalService::create([
'subscription_id' => $subscription->id,
'title_english' => $request->optional_service_title_english[$key],
'title_chinese' => $request->optional_service_title_chinese[$key],
'is_custom' => $request->optional_service_is_custom[$key] == 'yes' ? true : false,
'price' => $request->optional_service_is_custom[$key] == 'yes' ? 0 : $request->optional_service_price[$key],
'period' => $request->optional_service_period[$key],
'custom_description' => $request->optional_service_is_custom[$key] == 'yes' ? $request->optional_service_custom_description[$key] : null,
]);
}
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
public function edit(Subscription $subscription)
{
return view('theme::cms.subscriptions.management.edit', [
'subscription' => $subscription,
]);
}
public function update(Request $request, Subscription $subscription)
{
$validator = Validator::make($request->all(), [
'status' => 'required|in:active,inactive',
'name_english' => 'required|string',
'name_chinese' => 'required|string',
'period_english' => 'required|in:annually,monthly,daily',
'period_chinese' => 'required|in:每年,每月,每日',
'description_english' => 'required|string',
'description_chinese' => 'required|string',
'price' => 'required|numeric',
'basic_service_title_english' => 'required|array',
'basic_service_title_chinese' => 'required|array',
'basic_service_list_title_english' => 'required|array',
'basic_service_list_title_chinese' => 'required|array',
'optional_service_title_english' => 'required|array',
'optional_service_title_chinese' => 'required|array',
'optional_service_is_custom' => 'required|array',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
$subscription->name_english = $request->name_english;
$subscription->name_chinese = $request->name_chinese;
$subscription->period_english = $request->period_english;
$subscription->period_chinese = $request->period_chinese;
$subscription->description_english = $request->description_english;
$subscription->description_chinese = $request->description_chinese;
$subscription->price = $request->price;
$subscription->status = $request->status;
$subscription->save();
foreach ($subscription->basicServices as $key => $basicService) {
$basicService->lists()->delete();
}
$subscription->basicServices()->delete();
foreach ($request->basic_service_title_english as $key => $basic_service_title_english) {
$subscriptionBasicService = SubscriptionBasicService::create([
'subscription_id' => $subscription->id,
'title_english' => $request->basic_service_title_english[$key],
'title_chinese' => $request->basic_service_title_chinese[$key],
]);
foreach ($request->basic_service_list_title_english[$key] as $key2 => $basic_service_list_title_english) {
SubscriptionBasicServiceList::create([
'subscription_basic_service_id' => $subscriptionBasicService->id,
'title_english' => $request->basic_service_list_title_english[$key][$key2],
'title_chinese' => $request->basic_service_list_title_chinese[$key][$key2],
]);
}
}
$subscription->optionalServices()->delete();
foreach ($request->optional_service_title_english as $key => $optional_service_title_english) {
SubscriptionOptionalService::create([
'subscription_id' => $subscription->id,
'title_english' => $request->optional_service_title_english[$key],
'title_chinese' => $request->optional_service_title_chinese[$key],
'is_custom' => $request->optional_service_is_custom[$key] == 'yes' ? true : false,
'price' => $request->optional_service_is_custom[$key] == 'yes' ? 0 : $request->optional_service_price[$key],
'period' => $request->optional_service_period[$key],
'custom_description' => $request->optional_service_is_custom[$key] == 'yes' ? $request->optional_service_custom_description[$key] : null,
]);
}
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class TermsAndConditionsController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::cms.terms-and-conditions.index', [
'siteSetting' => $siteSetting,
]);
}
public function update(Request $request)
{
$validator = Validator::make($request->all(), [
'terms_and_conditions_english' => 'required',
'terms_and_conditions_chinese' => 'required',
]);
if ($validator->fails()) {
return redirect()->back()->with(['message' => __('Fill up all required fields!'), 'message_type' => 'danger', 'show_toast' => true]);
}
else {
$siteSetting = SiteSetting::latest()->first();
if ($siteSetting) {
$siteSetting->update($request->all());
}
else {
SiteSetting::create($request->all());
}
return redirect()->back()->with(['message' => __('Terms and conditions has successfully updated!'), 'message_type' => 'success', 'show_toast' => true]);
}
}
}

View File

@@ -0,0 +1,314 @@
<?php
namespace Wave\Http\Controllers\CMS;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\UserAccessLog;
use App\Models\Role;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Wave\Notifications\VerifyEmail;
use Yajra\DataTables\Facades\DataTables;
class UserController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$roles = Role::whereIn('id', [
Role::IT_PERSONNEL_ROLE,
Role::NUMSTATION_MANAGER_ROLE,
Role::NUMSTATION_STAFF_ROLE,
])->get();
return view('theme::cms.users.index')->with([
'roles' => $roles,
]);
}
public function table()
{
$users = User::query()
->select(
'users.id',
'users.first_name',
'users.last_name',
'users.phone',
'users.email',
'roles.display_name',
'users.status',
)
->leftJoin('roles', 'users.role_id', '=', 'roles.id')
->whereIn('users.role_id', [
Role::IT_PERSONNEL_ROLE,
Role::NUMSTATION_MANAGER_ROLE,
Role::NUMSTATION_STAFF_ROLE,
]);
// ->whereNot('users.id', auth()->user()->id);
return Datatables::of($users)
->escapeColumns(['id'])
->addColumn('status', function ($user) {
$status = $user->status;
if ($status == 'active') {
$status = '<span class="success item-list-note">' . ucwords($status) . '</span>';
}
else if ($status == 'inactive') {
$status = '<span class="failed item-list-note">' . ucwords($status) . '</span>';
}
return $status;
})
->addColumn('actions', function ($user) {
$suspendAction = '';
$activateAction = '';
$removeAction = '';
$editUserAction = '';
if (auth()->user()->userRole->hasAccess('manage-user-list-and-access-log')) {
$suspendAction = '<a class="dropdown-item suspend-user" href="#" data-action="' . route('cms.users.suspend', $user->id) . '">' . __("Suspend user") . '</a>';
$activateAction = '<a class="dropdown-item activate-user" href="#" data-action="' . route('cms.users.activate', $user->id) . '">' . __("Activate user") . '</a>';
$removeAction = '<a class="dropdown-item remove-user" href="#" data-action="' . route('cms.users.destroy', $user->id) . '">' . __("Remove user") . '</a>';
$editUserAction = '<a class="dropdown-item edit-user" href="#" data-action-show="' . route('cms.users.show', $user->id) . '" data-action-update="' . route('cms.users.update', $user->id) . '">' . __("Edit user") . '</a>';
}
$viewUserLogAction = '<a class="dropdown-item view-user-log" data-action="' . route("cms.users.accessLogsTable", $user->id) . '" href="#">' . __("View user log") . '</a>';
$actions = '
<div class="dropdown non-custom">
<button type="button" data-bs-toggle="dropdown" aria-expanded="false"><img class="max-25" src="' . asset('themes/tailwind/images/more.svg') . '"></button>
<div class="dropdown-menu">
' . ($user->status == 'active' ? $suspendAction : $activateAction) . '
' . $removeAction . '
' . $viewUserLogAction . '
' . $editUserAction . '
</div>
</div>
';
return $actions;
})
->make(true);
}
public function accessLogsTable($userId = null)
{
$logs = UserAccessLog::query()
->select(
'users.email',
'user_access_logs.created_at',
'user_access_logs.event',
'user_access_logs.description',
'user_access_logs.status',
)
->leftJoin('users', 'user_access_logs.user_id', '=', 'users.id')
->when($userId, function ($query) use ($userId) {
$query->where('users.id', $userId);
})
->when(! $userId, function ($query) use ($userId) {
$query->whereIn('users.role_id', [
Role::IT_PERSONNEL_ROLE,
Role::NUMSTATION_MANAGER_ROLE,
Role::NUMSTATION_STAFF_ROLE,
]);
});
return Datatables::of($logs)
->escapeColumns(['id'])
->addColumn('date', function ($log) {
return date('Ymd', strtotime($log->created_at));
})
->addColumn('time', function ($log) {
return date('H:i', strtotime($log->created_at));
})
->addColumn('status', function ($log) {
return '<span class="' . $log->status . ' item-list-note">' . ucwords($log->status) . '</span>';
})
->make(true);
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'phone' => 'required|string',
'password' => 'required|string|min:6|confirmed',
'role_id' => 'required|int',
'status' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
event(new Registered($user = $this->create($request->all())));
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
public function suspend(User $user)
{
$user->status = 'inactive';
$user->save();
return response()->json([
'success' => true,
'message' => __("User has successfully suspended!"),
]);
}
public function activate(User $user)
{
$user->status = 'active';
$user->save();
return response()->json([
'success' => true,
'message' => __("User has successfully activated!"),
]);
}
public function destroy(User $user)
{
$user->delete();
return response()->json([
'success' => true,
'message' => __("User has successfully removed!"),
]);
}
public function show(User $user)
{
return response()->json([
'success' => true,
'message' => __("User details has successfully retrieved!"),
'user' => $user,
]);
}
public function update(User $user, Request $request)
{
$validator = Validator::make($request->all(), [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users,email,' . $user->id,
'phone' => 'required|string',
'current_password' => 'nullable|string|min:6',
'password' => 'nullable|string|min:6|confirmed',
'role_id' => 'required|int',
'status' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
else {
if ($request->current_password && !\Hash::check($request->current_password, $user->password)) {
return response()->json([
'success' => false,
'message' => __('The current password is incorrect.'),
]);
}
$userData = $request->all();
if ($userData['password']) {
$userData['password'] = bcrypt($userData['password']);
}
else {
unset($userData['password']);
}
unset($userData['current_password']);
unset($userData['password_confirmation']);
$user->update($userData);
return response()->json([
'success' => true,
'message' => __("All changes have been saved!"),
]);
}
}
private function create(array $data)
{
$verification_code = Str::random(30);
$verified = 0;
$username = $this->getUniqueUsernameFromEmail($data['email']);
$username_original = $username;
$counter = 1;
while(User::where('username', '=', $username)->first()){
$username = $username_original . (string)$counter;
$counter += 1;
}
$user = User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'name' => $data['first_name'] . ' ' . $data['last_name'],
'email' => $data['email'],
'username' => $username,
'password' => bcrypt($data['password']),
'role_id' => $data['role_id'],
'verification_code' => $verification_code,
'verified' => $verified,
'trial_ends_at' => null,
'phone' => $data['phone'],
'company_id' => (isset($data['company_id']) ? $data['company_id'] : null)
]);
$this->sendVerificationEmail($user);
return $user;
}
private function getUniqueUsernameFromEmail($email)
{
$username = strtolower(trim(Str::slug(explode('@', $email)[0])));
$new_username = $username;
$user_exists = \Wave\User::where('username', '=', $username)->first();
$counter = 1;
while (isset($user_exists->id) ) {
$new_username = $username . $counter;
$counter += 1;
$user_exists = \Wave\User::where('username', '=', $new_username)->first();
}
$username = $new_username;
if(strlen($username) < 4){
$username = $username . uniqid();
}
return strtolower($username);
}
private function sendVerificationEmail($user){
Notification::route('mail', $user->email)->notify(new VerifyEmail($user));
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Wave\Http\Controllers\CompanySecretary;
use App\Http\Controllers\Controller;
class CompanyController extends Controller
{
public function changeCompanyName()
{
return view('theme::company-secretary.change-company-name');
}
public function changeCompanyAddress()
{
return view('theme::company-secretary.change-company-address');
}
public function transferOfShares()
{
return view('theme::company-secretary.transfer-of-shares');
}
public function serviceEnquiry()
{
return view('theme::company-secretary.service-enquiry');
}
public function enquiryHistory()
{
return view('theme::company-secretary.enquiry-history');
}
public function enquiryDetails()
{
return view('theme::company-secretary.enquiry-details');
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Wave\Http\Controllers\CompanySecretary;
use App\Http\Controllers\Controller;
class ServiceRecordController extends Controller
{
public function serviceList()
{
return view('theme::company-secretary.service-list');
}
public function documentLibrary()
{
return view('theme::company-secretary.document-library');
}
public function digitalTransformation()
{
return view('theme::company-secretary.digital-transformation');
}
public function serviceDraft()
{
return view('theme::company-secretary.service-draft');
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
class HomeController extends Controller
{
/**
* Show the application dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// if(setting('auth.dashboard_redirect', true) != "null"){
if(!Auth::guest()){
// return redirect('dashboard');
return redirect(Auth::user()->getRedirectRoute());
}
// }
return redirect(route('login'));
$seo = [
'title' => setting('site.title', 'Laravel Wave'),
'description' => setting('site.description', 'Software as a Service Starter Kit'),
'image' => url('/og_image.png'),
'type' => 'website'
];
return view('theme::home', compact('seo'));
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class NotificationController extends Controller
{
public function index(){
return view('theme::notifications.index');
}
public function delete(Request $request, $id){
$notification = auth()->user()->notifications()->where('id', $id)->first();
if ($notification){
$notification->delete();
return response()->json(['type' => 'success', 'message' => 'Marked Notification as Read', 'listid' => $request->listid]);
}
else {
return response()->json(['type' => 'error', 'message' => 'Could not find the specified notification.']);
}
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
use Wave\Page;
class PageController extends Controller
{
public function page($slug){
$page = Page::where('slug', '=', $slug)->firstOrFail();
$seo = [
'seo_title' => $page->title,
'seo_description' => $page->meta_description,
];
return view('theme::page', compact('page', 'seo'));
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
class ProfileController extends Controller
{
public function index($username){
$user = config('wave.user_model')::where('username', '=', $username)->firstOrFail();
return view('theme::profile', compact('user'));
}
}

View File

@@ -0,0 +1,131 @@
<?php
namespace Wave\Http\Controllers\Settings;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
use App\Models\User;
use App\Models\UserNotificationSetting;
use App\Models\OnlineHelp;
use App\Models\UserEnquiry;
use Illuminate\Http\Request;
class SettingsController extends Controller
{
public function main()
{
$current_user = \Auth::user();
$siteSetting = SiteSetting::latest()->first();
$faq_lists = OnlineHelp::orderBy('sort', 'asc')->get();
return view('theme::settings.main', [
'siteSetting' => $siteSetting,
'user_push_notification' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_PUSH_NOTIFICATION)->first(),
'user_bookkeeping_queue' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_BOOKKEEPING_QUEUE)->first(),
'user_company_security_queue' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_COMPANY_SECURTY_QUEUE)->first(),
'user_chat_room' => UserNotificationSetting::where('user_id', $current_user->id)->where('notification', UserNotificationSetting::USER_CHAT_ROOM)->first(),
'UserNotificationSetting' => UserNotificationSetting::class,
'faq_lists' => $faq_lists,
]);
}
public function myEnquiries()
{
$current_user = \Auth::user();
$enquiry_list = UserEnquiry::where('user_id', $current_user->id)->get();
return view('theme::settings.my-enquiries', [
'enquiry_list' => $enquiry_list,
]);
}
public function enquiryDetails()
{
return view('theme::settings.enquiry-details');
}
public function toggleNotificationStatus($notification)
{
$current_user = \Auth::user();
$set_status = true;
$check_settings = UserNotificationSetting::where('user_id', $current_user->id)->where('notification', $notification)->first();
if ($check_settings) {
$set_status = !$check_settings->is_active;
}
UserNotificationSetting::updateOrCreate(
[
'user_id' => $current_user->id,
'notification' => $notification,
],
[
'is_active' => $set_status,
],
);
return response()->json([
'success' => true,
'message' => 'notification status successfully updated',
]);
}
public function changePassword(Request $request)
{
$request->validate([
'password' => 'required',
'new_password' => 'required',
'confirm_password' => 'required',
]);
$current_user = \Auth::user();
$new_password = \Hash::make($request->get('new_password'));
if (! \Hash::check($request->get('password'), $current_user->password)) {
return response()->json([
'success' => false,
'message' => 'Invalid current password.',
]);
}
if (! \Hash::check($request->get('confirm_password'), $new_password)) {
return response()->json([
'success' => false,
'message' => 'Password did not match.',
]);
}
User::where('id', $current_user->id)->update([
'password' => $new_password,
]);
return response()->json([
'success' => true,
'message' => 'Password successfully changed.',
]);
}
public function addEnquiry(Request $request)
{
$request->validate([
'name' => 'required',
'phone' => 'required',
'email' => 'required',
'category' => 'required',
'title' => 'required',
'message' => 'required',
]);
$current_user = \Auth::user();
$data = $request->all();
$data['user_id'] = $current_user->id;
UserEnquiry::create($data);
return response()->json([
'success' => true,
'message' => 'Enquiry successfully created.',
]);
}
}

View File

@@ -0,0 +1,147 @@
<?php
namespace Wave\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use TCG\Voyager\Http\Controllers\Controller;
use Wave\ApiKey;
use Wave\KeyValue;
class SettingsController extends Controller
{
public function index($section = ''){
if(empty($section)){
return redirect(route('wave.settings', 'profile'));
}
return view('theme::settings.index', compact('section'));
}
public function profilePut(Request $request){
$request->validate([
'name' => 'required|string',
'email' => 'sometimes|required|email|unique:users,email,' . Auth::user()->id,
'username' => 'sometimes|required|unique:users,username,' . Auth::user()->id,
'avatar' => 'nullable|base64image'
],
[
'avatar.base64image' => 'The avatar must be a valid image.'
]);
$authed_user = auth()->user();
$authed_user->name = $request->name;
$authed_user->email = $request->email;
if($request->avatar){
$authed_user->avatar = $this->saveAvatar($request->avatar, $authed_user->username);
}
$authed_user->save();
foreach(config('wave.profile_fields') as $key){
if(isset($request->{$key})){
$type = $key . '_type__wave_keyvalue';
if($request->{$type} == 'checkbox'){
if(!isset($request->{$key})){
$request->request->add([$key => null]);
}
}
$row = (object)['field' => $key, 'type' => $request->{$type}, 'details' => ''];
$value = $this->getContentBasedOnType($request, 'themes', $row);
if(!is_null($authed_user->keyValue($key))){
$keyValue = KeyValue::where('keyvalue_id', '=', $authed_user->id)->where('keyvalue_type', '=', 'users')->where('key', '=', $key)->first();
$keyValue->value = $value;
$keyValue->type = $request->{$type};
$keyValue->save();
} else {
KeyValue::create(['type' => $request->{$type}, 'keyvalue_id' => $authed_user->id, 'keyvalue_type' => 'users', 'key' => $key, 'value' => $value]);
}
} else {
if(!is_null($authed_user->keyValue($key))){
$keyValue = KeyValue::where('keyvalue_id', '=', $authed_user->id)->where('keyvalue_type', '=', 'users')->where('key', '=', $key)->first();
$keyValue->delete();
}
}
}
return back()->with(['message' => 'Successfully updated user profile', 'message_type' => 'success']);
}
public function securityPut(Request $request){
$validator = Validator::make($request->all(), [
'current_password' => 'required|current_password',
'password' => 'required|confirmed|min:'.config('wave.auth.min_password_length'),
]);
if ($validator->fails()) {
return back()->with(['message' => $validator->errors()->first(), 'message_type' => 'danger']);
}
auth()->user()->forceFill([
'password' => bcrypt($request->password)
])->save();
return back()->with(['message' => 'Successfully updated your password.', 'message_type' => 'success']);
}
public function paymentPost(Request $request){
$subscribed = auth()->user()->updateCard($request->paymentMethod);
}
public function apiPost(Request $request){
$request->validate([
'key_name' => 'required'
]);
$apiKey = auth()->user()->createApiKey(Str::slug($request->key_name));
if(isset($apiKey->id)){
return back()->with(['message' => 'Successfully created new API Key', 'message_type' => 'success']);
} else {
return back()->with(['message' => 'Error Creating API Key, please make sure you entered a valid name.', 'message_type' => 'danger']);
}
}
public function apiPut(Request $request, $id = null){
if(is_null($id)){
$id = $request->id;
}
$apiKey = ApiKey::findOrFail($id);
if($apiKey->user_id != auth()->user()->id){
return back()->with(['message' => 'Canot update key name. Invalid User', 'message_type' => 'danger']);
}
$apiKey->name = Str::slug($request->key_name);
$apiKey->save();
return back()->with(['message' => 'Successfully update API Key name.', 'message_type' => 'success']);
}
public function apiDelete(Request $request, $id = null){
if(is_null($id)){
$id = $request->id;
}
$apiKey = ApiKey::findOrFail($id);
if($apiKey->user_id != auth()->user()->id){
return back()->with(['message' => 'Canot delete Key. Invalid User', 'message_type' => 'danger']);
}
$apiKey->delete();
return back()->with(['message' => 'Successfully Deleted API Key', 'message_type' => 'success']);
}
private function saveAvatar($avatar, $filename){
$path = 'avatars/' . $filename . '.png';
Storage::disk(config('voyager.storage.disk'))->put($path, file_get_contents($avatar));
return $path;
}
public function invoice(Request $request, $invoiceId) {
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => setting('site.title', 'Wave'),
'product' => ucfirst(auth()->user()->role->name) . ' Subscription Plan',
]);
}
}

View File

@@ -0,0 +1,225 @@
<?php
namespace Wave\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use TCG\Voyager\Models\Role;
use Wave\PaddleSubscription;
use Carbon\Carbon;
use Wave\Plan;
use Wave\User;
class SubscriptionController extends Controller
{
private $paddle_checkout_url;
private $paddle_vendors_url;
private $endpoint = 'https://vendors.paddle.com/api';
private $vendor_id;
private $vendor_auth_code;
public function __construct(){
$this->vendor_auth_code = config('wave.paddle.auth_code');
$this->vendor_id = config('wave.paddle.vendor');
$this->paddle_checkout_url = (config('wave.paddle.env') == 'sandbox') ? 'https://sandbox-checkout.paddle.com/api' : 'https://checkout.paddle.com/api';
$this->paddle_vendors_url = (config('wave.paddle.env') == 'sandbox') ? 'https://sandbox-vendors.paddle.com/api' : 'https://vendors.paddle.com/api';
}
public function webhook(Request $request){
// Which alert/event is this request for?
$alert_name = $request->alert_name;
$subscription_id = $request->subscription_id;
$status = $request->status;
// Respond appropriately to this request.
switch($alert_name) {
case 'subscription_created':
break;
case 'subscription_updated':
break;
case 'subscription_cancelled':
$this->cancelSubscription($subscription_id);
return response()->json(['status' => 1]);
break;
case 'subscription_payment_succeeded':
break;
case 'subscription_payment_failed':
$this->cancelSubscription($subscription_id);
return response()->json(['status' => 1]);
break;
}
}
public function cancel(Request $request){
$this->cancelSubscription($request->id);
return response()->json(['status' => 1]);
}
private function cancelSubscription($subscription_id){
$subscription = PaddleSubscription::where('subscription_id', $subscription_id)->first();
$subscription->cancelled_at = Carbon::now();
$subscription->status = 'cancelled';
$subscription->save();
$user = User::find( $subscription->user_id );
$cancelledRole = Role::where('name', '=', 'cancelled')->first();
$user->role_id = $cancelledRole->id;
$user->save();
}
public function checkout(Request $request){
//PaddleSubscriptions
$response = Http::get($this->paddle_checkout_url . '/1.0/order?checkout_id=' . $request->checkout_id);
$status = 0;
$message = '';
$guest = (auth()->guest()) ? 1 : 0;
if( $response->successful() ){
$resBody = json_decode($response->body());
if(isset($resBody->order)){
$order = $resBody->order;
$plans = Plan::all();
if($order->is_subscription && $plans->contains('plan_id', $order->product_id) ){
$subscriptionUser = Http::post($this->paddle_vendors_url . '/2.0/subscription/users', [
'vendor_id' => $this->vendor_id,
'vendor_auth_code' => $this->vendor_auth_code,
'subscription_id' => $order->subscription_id
]);
$subscriptionData = json_decode($subscriptionUser->body());
$subscription = $subscriptionData->response[0];
if(auth()->guest()){
if(User::where('email', $subscription->user_email)->exists()){
$user = User::where('email', $subscription->user_email)->first();
} else {
// create a new user
$registration = new \Wave\Http\Controllers\Auth\RegisterController;
$user_data = [
'name' => '',
'email' => $subscription->user_email,
'password' => Hash::make(uniqid())
];
$user = $registration->create($user_data);
Auth::login($user);
}
} else {
$user = auth()->user();
}
$plan = Plan::where('plan_id', $subscription->plan_id)->first();
// add associated role to user
$user->role_id = $plan->role_id;
$user->save();
$subscription = PaddleSubscription::create([
'subscription_id' => $order->subscription_id,
'plan_id' => $order->product_id,
'user_id' => $user->id,
'status' => 'active', // https://developer.paddle.com/reference/ZG9jOjI1MzU0MDI2-subscription-status-reference
'last_payment_at' => $subscription->last_payment->date,
'next_payment_at' => $subscription->next_payment->date,
'cancel_url' => $subscription->cancel_url,
'update_url' => $subscription->update_url
]);
$status = 1;
} else {
$message = 'Error locating that subscription product id. Please contact us if you think this is incorrect.';
}
} else {
$message = 'Error locating that order. Please contact us if you think this is incorrect.';
}
} else {
$message = $response->serverError();
}
return response()->json([
'status' => $status,
'message' => $message,
'guest' => $guest
]);
}
public function invoices(User $user){
$invoices = [];
if(isset($user->subscription->subscription_id)){
$response = Http::post($this->paddle_vendors_url . '/2.0/subscription/payments', [
'vendor_id' => $this->vendor_id,
'vendor_auth_code' => $this->vendor_auth_code,
'subscription_id' => $user->subscription->subscription_id,
'is_paid' => 1
]);
$invoices = json_decode($response->body());
}
return $invoices;
}
public function switchPlans(Request $request){
$plan = Plan::where('plan_id', $request->plan_id)->first();
if(isset($plan->id)){
// Update the user plan with Paddle
$response = Http::post($this->paddle_vendors_url . '/2.0/subscription/users/update', [
'vendor_id' => $this->vendor_id,
'vendor_auth_code' => $this->vendor_auth_code,
'subscription_id' => $request->user()->subscription->subscription_id,
'plan_id' => $request->plan_id
]);
if($response->successful()){
$body = $response->json();
if($body['success']){
// Next, update the user role associated with the updated plan
$request->user()->forceFill([
'role_id' => $plan->role_id
])->save();
// And, update the subscription with the updated plan.
$request->user()->subscription()->update([
'plan_id' => $request->plan_id
]);
return back()->with(['message' => 'Successfully switched to the ' . $plan->name . ' plan.', 'message_type' => 'success']);
}
}
}
return back()->with(['message' => 'Sorry, there was an issue updating your plan.', 'message_type' => 'danger']);
}
}

View File

@@ -0,0 +1,266 @@
<?php
namespace Wave\Http\Controllers\User;
use App\Models\BookkeepingDocumentCategory;
use App\Models\BookkeepingDocument;
use App\Models\CompanySubscription;
use App\Models\Subscription;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
class BookKeepingController extends Controller
{
public function accountOverview()
{
$current_user = \Auth::user();
$subscription = CompanySubscription::where('company_id', $current_user->company_id)->first();
if (! $subscription) {
return redirect(route('wave.user.book-keeping.packages'));
}
return view('theme::user.book-keeping.account-overview');
}
public function list()
{
$current_user = \Auth::user();
$document_category = BookkeepingDocumentCategory::all();
$documents_list = BookkeepingDocument::with('category')->where('company_id', $current_user->company_id)->where('status', '<>', 'completed')->get();
$documents_complete = BookkeepingDocument::with('category')->where('company_id', $current_user->company_id)->where('status', 'completed')->get();
return view('theme::user.book-keeping.list',[
'document_category' => $document_category,
'documents_list' => $documents_list,
'documents_complete' => $documents_complete,
]);
}
public function documentLibrary(Request $request)
{
$current_user = \Auth::user();
$documents = BookkeepingDocument::with('category')->where('company_id', $current_user->company_id);
if (! is_null($request->get('s'))) {
$search = $request->get('s');
$documents->where(function($q) use($search){
$q->where('file_name', 'LIKE', '%' . $search . '%')
->orWhere('batch_name', 'LIKE', '%' . $search . '%')
->orWhere('description', 'LIKE', '%' . $search . '%');
});
}
if (! is_null($request->get('status'))) {
$status = $request->get('status');
if ($status !== 'all') {
$documents->where('status', $status);
}
}
if (! is_null($request->get('category_id'))) {
$category_id = $request->get('category_id');
if ($category_id !== 'all') {
$documents->where('bookkeeping_document_category_id', $category_id);
}
}
if (! is_null($request->get('fix_date'))) {
$fix_date = $request->get('fix_date');
if ($fix_date !== 'all' && $fix_date !== 'custom') {
if ($fix_date === 'today') {
$date = \Carbon\Carbon::today();
} else {
$date = \Carbon\Carbon::today()->subDays($fix_date);
}
$documents->where('created_at','>=',$date);
}
if ($fix_date === 'custom') {
if (! is_null($request->get('data_from')) && ! is_null($request->get('date_to'))) {
$documents->whereBetween('created_at', [
Carbon::parse($request->get('data_from'))->format('Y-m-d'),
Carbon::parse($request->get('date_to'))->format('Y-m-d'),
]);
}
}
}
$documents = $documents->paginate(10);
$document_category = BookkeepingDocumentCategory::all();
return view('theme::user.book-keeping.document-library', [
'documents' => $documents,
'document_category' => $document_category,
'search' => is_null($request->get('s')) ? '' : $request->get('s'),
]);
}
public function packages()
{
return view('theme::user.book-keeping.packages');
}
public function checkout($package_id)
{
$subscription = Subscription::where('id', $package_id)->firstOrFail();
return view('theme::user.book-keeping.checkout', [
'subscription' => $subscription,
]);
}
public function checkoutPaymentSuccess()
{
$current_user = \Auth::user();
$subscription = CompanySubscription::where('company_id', $current_user->company_id)->first();
if (! $subscription) {
CompanySubscription::create([
'company_id'=> $current_user->company_id,
'subscription_id'=> 1,
'stripe_subscription_id'=> 1,
'status'=> 1,
]);
}
return view('theme::user.book-keeping.checkout-payment-success');
}
public function addBookkeepingDocument(Request $request)
{
$request->validate([
'document' => 'required',
'name' => 'required',
'description' => 'required',
'bookkeeping_document_category_id' => 'required',
]);
$current_user = $request->user();
$file = $request->file('document');
$file_name = $request->file('document')->getClientOriginalName();
$sanitizedFileName = str_replace(' ', '_', $file_name); // Replac
$fileName = time() . '_' . $sanitizedFileName;
$bookkeepingDocument = BookkeepingDocument::create([
'user_id' => $current_user->id,
'company_id' => $current_user->company_id,
'batch_name' => $request->name,
'remark' => $request->description,
'file_name' => $fileName,
'bookkeeping_document_category_id' => $request->bookkeeping_document_category_id,
]);
$filePath = $bookkeepingDocument->file_path;
\Storage::disk('s3')->put($filePath, file_get_contents($file), 'public');
$url = env('AWS_ENDPOINT').env('AWS_BUCKET').'/'.$filePath;
$file_size = convertToReadableSize(\Storage::disk('s3')->size($filePath));
$bookkeepingDocument->update([
'url' => $url,
'file_size' => $file_size,
]);
return response()->json([
'success' => true,
'message' => 'document successfully added',
]);
}
public function getDocumentList(Request $request)
{
$current_user = $request->user();
$documents_list = BookkeepingDocument::with('category')->where('company_id', $current_user->company_id)->where('status', '<>', 'completed')->get();
$documents_complete = BookkeepingDocument::with('category')->where('company_id', $current_user->company_id)->where('status', 'completed')->get();
return response()->json([
'success' => true,
'documents_in_queue' => $documents_list,
'documents_completed' => $documents_complete,
]);
}
public function getDocumentCategories(Request $request)
{
$current_user = $request->user();
$document_category = BookkeepingDocumentCategory::all();
return response()->json([
'success' => true,
'categories' => $document_category,
]);
}
public function viewBookkeepingDocument(Request $request, $document_id)
{
$document = BookkeepingDocument::with('category')->where('id', $document_id)->first();
return response()->json([
'success' => true,
'document' => $document,
]);
}
public function downloadDocument($document_id)
{
$asset = BookkeepingDocument::find($document_id);
return response()->streamDownload(function () use ($asset) {
echo file_get_contents(\Storage::disk('s3')->url($asset->url));
} , $asset->file_name);
}
public function getDocumentLibrary(Request $request)
{
$current_user = $request->user();
$documents = BookkeepingDocument::with('category')->where('company_id', $current_user->company_id);
if (! is_null($request->get('s'))) {
$search = $request->get('s');
$documents->where(function($q) use($search){
$q->where('file_name', 'LIKE', '%' . $search . '%')
->orWhere('name', 'LIKE', '%' . $search . '%')
->orWhere('remark', 'LIKE', '%' . $search . '%');
});
}
if (! is_null($request->get('status'))) {
$status = $request->get('status');
if ($status !== 'all') {
$documents->where('status', $status);
}
}
if (! is_null($request->get('category_id'))) {
$category_id = $request->get('category_id');
if ($category_id !== 'all') {
$documents->where('bookkeeping_document_category_id', $category_id);
}
}
if (! is_null($request->get('fix_date'))) {
$fix_date = $request->get('fix_date');
if ($fix_date !== 'all' && $fix_date !== 'custom') {
if ($fix_date === 'today') {
$date = \Carbon\Carbon::today();
} else {
$date = \Carbon\Carbon::today()->subDays($fix_date);
}
$documents->where('created_at','>=',$date);
}
if ($fix_date === 'custom') {
if (! is_null($request->get('data_from')) && ! is_null($request->get('date_to'))) {
$documents->whereBetween('created_at', [
Carbon::parse($request->get('data_from'))->format('Y-m-d'),
Carbon::parse($request->get('date_to'))->format('Y-m-d'),
]);
}
}
}
$documents = $documents->paginate(10);
return response()->json([
'success' => true,
'documents' => $documents,
]);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Wave\Http\Controllers\User;
use App\Http\Controllers\Controller;
class CompanySecretaryController extends Controller
{
public function index()
{
return view('theme::user.company-secretary.index');
}
public function limitedCompany()
{
return view('theme::user.company-secretary.limited-company');
}
public function changeDirector()
{
return view('theme::user.company-secretary.change-director');
}
public function changeSecretary()
{
return view('theme::user.company-secretary.change-secretary');
}
public function changeParticulars()
{
return view('theme::user.company-secretary.change-particulars');
}
public function resignation()
{
return view('theme::user.company-secretary.resignation');
}
public function checkout()
{
return view('theme::user.company-secretary.checkout');
}
public function checkoutPaymentSuccess()
{
return view('theme::user.company-secretary.checkout-payment-success');
}
public function checkoutPaymentFailed()
{
return view('theme::user.company-secretary.checkout-payment-failed');
}
}

View File

@@ -0,0 +1,398 @@
<?php
namespace Wave\Http\Controllers\User;
use App\Events\ChatEvent;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
use App\Models\Role;
use App\Models\User;
use App\Models\Permission;
use App\Models\PermissionGroup;
use App\Models\PermissionRole;
use App\Models\UserAccessLog;
use App\Models\ServiceChat;
use App\Models\ServiceChatMessage;
use App\Models\CompanySubscription;
use App\Models\Company;
use App\Models\CompanyMember;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Notification;
use Wave\Notifications\VerifyEmail;
class DashboardController extends Controller
{
public function index()
{
$current_user = \Auth::user();
return view('theme::user.dashboard');
}
public function generalInformation()
{
$current_user = \Auth::user();
$company = Company::where('id', $current_user->company_id)->first();
$company_members = CompanyMember::where('company_id', $current_user->company_id)->get();
return view('theme::user.general-information',[
'company' => $company,
'company_members' => $company_members,
]);
}
public function userManagement()
{
$roles_id = [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE, Role::BOOKKEEPER_ROLE, Role::COMPANY_SECRETARY_ROLE];
$current_user = \Auth::user();
$roles = Role::whereIn('id', $roles_id)->get();
$company_users = User::with('userRole')->where('company_id', $current_user->company_id)->get();
$user_ids = User::where('company_id', $current_user->company_id)->pluck('id');
$user_logs = UserAccessLog::whereIn('user_id', $user_ids)->orderBy('created_at', 'desc')->get();
$permission_group = PermissionGroup::with('permissions')->where('platform', 'client')->get();
return view('theme::user.user-management', [
'roles' => $roles,
'company_users' => $company_users,
'user_logs' => $user_logs,
'permission_group' => $permission_group,
]);
}
public function userTermsAndCondition()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::user.terms-and-condition', [
'siteSetting' => $siteSetting,
]);
}
public function userPrivacyPolicy()
{
$siteSetting = SiteSetting::latest()->first();
return view('theme::user.privacy-policy', [
'siteSetting' => $siteSetting,
]);
}
public function createUser(Request $request)
{
$request->validate([
'email' => 'required|unique:users,email',
'first_name' => 'required',
'last_name' => 'required',
'password' => 'required',
'phone' => 'required',
'role_id' => 'required',
'status' => 'required',
]);
$verification_code = \Str::random(30);
$verified = false;
$current_user = $request->user();
$user_data = $request->all();
$user_data['password'] = \Hash::make($request->get('password'));
$user_data['name'] = $request->get('first_name') . ' ' . $request->get('last_name');
$user_data['username'] = $request->get('first_name') . \Str::random(5);
$user_data['company_id'] = $current_user->company_id;
$new_user = User::create($user_data);
$new_user->verification_code = $verification_code;
$new_user->save();
Notification::route('mail', $request->get('email'))->notify(new VerifyEmail($new_user));
return response()->json([
'success' => true,
'message' => 'user successfully created',
]);
}
public function updateUser(Request $request)
{
$request->validate([
'user_id' => 'required',
'email' => 'required',
'first_name' => 'required',
'last_name' => 'required',
'phone' => 'required',
'role_id' => 'required',
'status' => 'required',
]);
$email_exist = User::where('email', $request->get('email'))->where('id', '<>', $request->get('user_id'))->first();
if ($email_exist) {
return response()->json([
'success' => false,
'message' => 'Email already exist!',
]);
}
User::where('id', $request->get('user_id'))->update([
'email' => $request->get('email'),
'first_name' => $request->get('first_name'),
'last_name' => $request->get('last_name'),
'phone' => $request->get('phone'),
'role_id' => $request->get('role_id'),
'status' => $request->get('status'),
]);
if ($request->get('password') === $request->get('confirm_password')) {
User::where('id', $request->get('user_id'))->update([
'password' => \Hash::make($request->get('password')),
]);
}
return response()->json([
'success' => true,
'message' => 'user successfully updated',
]);
}
public function deleteUser(Request $request)
{
$request->validate([
'user_id' => 'required',
]);
User::where('id', $request->get('user_id'))->delete();
return response()->json([
'success' => true,
'message' => 'user successfully deleted',
]);
}
public function getChatMessages($serviceType)
{
$newCollection = collect();
$chat = ServiceChat::where('company_id', request()->user()->company_id)
->where('user_id', request()->user()->id)
->where('service_type', $serviceType)
->first();
if (! $chat) {
$chat = new ServiceChat();
$chat->company_id = request()->user()->company_id;
$chat->user_id = request()->user()->id;
$chat->service_type = $serviceType;
$chat->save();
}
$messages = $chat ? $chat->messages : null;
if ($messages) {
$newCollection = $messages->map(function ($message) {
$message->date = $message->created_at->format('Y-m-d');
$message->is_own_message = request()->user()->id == $message->from_user_id ? true : false;
$message->elapsed_time = $message->elapsed_time;
$message->message = $message->is_file ? '<a href="' . $message->file_url . '" target="_blank">' . $message->file_name . '</a>' : $message->message;
return $message;
})
->groupBy('date')
->map(function ($message) {
return $message->flatmap(function ($item) use ($message) {
return [
'date' => $item->created_at->format('d F, Y'),
'messages' => $message,
];
});
})
->values()
->all();
}
return response()->json([
'success' => true,
'data' => $newCollection,
'chat_id' => $chat->id,
]);
}
public function sendChat(Request $request)
{
$chat = ServiceChat::where('company_id', $request->user()->company_id)
->where('user_id', $request->user()->id)
->where('service_type', $request->chat_service_type)
->first();
if (! $chat) {
$chat = new ServiceChat();
$chat->company_id = $request->user()->company_id;
$chat->user_id = $request->user()->id;
$chat->service_type = $request->chat_service_type;
$chat->save();
}
$messageFileName = '';
if ($request->hasFile('chat_message_file')) {
$file = $request->file('chat_message_file');
$messageFileName = $request->file('chat_message_file')->getClientOriginalName();
$file->storePubliclyAs($chat->folder_path, $messageFileName);
}
ServiceChatMessage::create([
'service_chat_id' => $chat->id,
'message' => $request->chat_message,
'from_user_id' => $request->user()->id,
'to_admin' => true,
'is_file' => $messageFileName ? true : false,
'file_name' => $messageFileName,
]);
ChatEvent::dispatch($chat->id, true);
storeUserNotification(null, 'Service Chat', $request->chat_message, 'Service Chat', true, $chat->id, 'service_chat');
return response()->json([
'success' => true,
]);
}
public function getUserList(Request $request)
{
$current_user = $request->user();
$company_users = User::with('userRole')->where('company_id', $current_user->company_id)->where('id', '<>', $current_user->id)->get();
return response()->json([
'status' => true,
'company_users' => $company_users,
]);
}
public function getUserData(Request $request, $user_id)
{
$current_user = $request->user();
$user = User::with('userRole')->where('company_id', $current_user->company_id)->where('id', $user_id)->first();
if ($user) {
return response()->json([
'status' => true,
'user' => $user,
]);
}
return response()->json([
'status' => false,
'message' => 'User doest not exist on this company',
]);
}
public function getCompanyUserRoles(Request $request)
{
$roles_id = [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE, Role::BOOKKEEPER_ROLE, Role::COMPANY_SECRETARY_ROLE];
$roles = Role::whereIn('id', $roles_id)->get();
return response()->json([
'status' => false,
'roles' => $roles,
]);
}
public function getCompanyUsersAccessLogs(Request $request)
{
$current_user = $request->user();
$user_ids = User::where('company_id', $current_user->company_id)->pluck('id');
$logs = UserAccessLog::whereIn('user_id', $user_ids)->get();
return response()->json([
'status' => false,
'logs' => $logs,
]);
}
public function getPermissionGroup(Request $request)
{
$group = PermissionGroup::with('permissions')->where('platform', 'client')->get();
return response()->json([
'status' => false,
'group' => $group,
]);
}
public function getPermissionOfRole(Request $request, $role_id)
{
$current_user = $request->user();
$permission = PermissionRole::with('permission')->where('company_id', $current_user->company_id)->where('role_id', $role_id)->get();
return response()->json([
'status' => false,
'permission' => $permission,
]);
}
public function addPermissionToRole(Request $request)
{
$request->validate([
'role_id' => 'required',
'permission_id' => 'required',
]);
$current_user = $request->user();
$permission = PermissionRole::where('role_id', $request->role_id)
->where('permission_id', $request->permission_id)
->where('company_id', $current_user->company_id)->first();
if (! $permission) {
PermissionRole::create([
'role_id' => $request->role_id,
'permission_id' => $request->permission_id,
'company_id' => $current_user->company_id,
]);
}
return response()->json([
'success' => true,
'message' => 'permission successfully added',
]);
}
public function removePermissionToRole(Request $request)
{
$request->validate([
'role_id' => 'required',
'permission_id' => 'required',
]);
$current_user = $request->user();
$permission = PermissionRole::where('role_id', $request->role_id)
->where('permission_id', $request->permission_id)
->where('company_id', $current_user->company_id)->delete();
return response()->json([
'success' => true,
'message' => 'permission successfully remove',
]);
}
public function roleHasPermission(Request $request)
{
$request->validate([
'role_id' => 'required',
'permission_id' => 'required',
]);
$current_user = $request->user();
$permission = PermissionRole::where('role_id', $request->role_id)
->where('permission_id', $request->permission_id)
->where('company_id', $current_user->company_id)->first();
if($permission) {
return response()->json([
'success' => true,
'message' => 'role has this permission',
]);
}
return response()->json([
'success' => false,
'message' => 'role dont have this permission',
]);
}
}

View File

@@ -0,0 +1,162 @@
<?php
namespace Wave\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Models\SiteSetting;
use App\Models\Role;
use App\Models\User;
use App\Models\Permission;
use App\Models\PermissionGroup;
use App\Models\PermissionRole;
use App\Models\UserAccessLog;
use App\Models\ServiceChat;
use App\Models\ServiceChatMessage;
use App\Models\Company;
use App\Models\CompanyDocument;
use App\Models\CompanyMember;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class GeneralInformationController extends Controller
{
public function saveCompanyDetails(Request $request)
{
$request->validate([
'name_english' => 'required',
'name_chinese' => 'required',
'registered_office_address_english' => 'required',
'registered_office_address_chinese' => 'required',
'br_number' => 'required',
]);
$current_user = $request->user();
Company::where('id', $current_user->company_id)->update([
'name_english' => $request->name_english,
'name_chinese' => $request->name_chinese,
'registered_office_address_english' => $request->registered_office_address_english,
'registered_office_address_chinese' => $request->registered_office_address_chinese,
'br_number' => $request->br_number,
]);
return response()->json([
'success' => true,
'message' => 'company successfully updated',
]);
}
public function updateCompanyMember(Request $request)
{
$request->validate([
'position' => 'required',
'title' => 'required',
'name_english' => 'required',
'name_chinese' => 'required',
'phone' => 'required',
'email' => 'required',
'document_type' => 'required',
'country' => 'required',
'address_english' => 'required',
'address_chinese' => 'required',
'year_date' => 'required',
'month_date' => 'required',
'day_date' => 'required',
'document_number' => 'required',
'city' => 'required',
]);
if ($request->member_id == 0) {
$member = new CompanyMember();
} else {
$member = CompanyMember::where('id', $request->member_id)->first();
}
$current_user = $request->user();
$member->company_id = $current_user->company_id;
$member->position = $request->position;
$member->title = $request->title;
$member->name_english = $request->name_english;
$member->name_chinese = $request->name_chinese;
$member->phone = $request->phone;
$member->email = $request->email;
$member->document_type = $request->document_type;
$member->document_number = $request->document_number;
$member->country = $request->country;
$member->address_english = $request->address_english;
$member->address_chinese = $request->address_chinese;
$member->year_date = $request->year_date;
$member->month_date = $request->month_date;
$member->day_date = $request->day_date;
$member->document_number = $request->document_number;
$member->city = $request->city;
$member->save();
if ($request->hasFile('document_file')) {
$file = $request->file('document_file');
$file_name = $request->file('document_file')->getClientOriginalName();
$sanitizedFileName = str_replace(' ', '_', $file_name); // Replac
$fileName = time() . '_' . $sanitizedFileName;
// $request->document_file->move(public_path('images'), $file_name);
$filePath = 'test/' . $fileName;
\Storage::disk('s3')->put($filePath, file_get_contents($file), 'public');
$url = env('AWS_ENDPOINT').env('AWS_BUCKET').'/'.$filePath;
CompanyDocument::create([
'company_id' => $current_user->company_id,
'member_id' => $member->id,
'filename' => $fileName,
'url' => $url,
]);
}
return response()->json([
'success' => true,
'message' => 'member successfully updated',
'data' => CompanyMember::with('documents')->where('id', $member->id)->first(),
]);
}
public function deleteMemberDocument(Request $request)
{
$request->validate([
'id' => 'required',
]);
$document = CompanyDocument::where('id', $request->id)->first();
if ($document) {
$document->delete();
} else {
return response()->json([
'success' => false,
'message' => 'file not found',
]);
}
return response()->json([
'success' => true,
'message' => 'file successfully deleted',
]);
}
public function getCompanyDetails(Request $request)
{
$current_user = $request->user();
$company = Company::where('id', $current_user->company_id)->first();
$company_members = CompanyMember::with('documents')->where('company_id', $current_user->company_id)->get();
return response()->json([
'success' => true,
'message' => '',
'data' => array(
'company' => $company,
'company_members' => $company_members,
),
]);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Wave\Http\Controllers\User;
use App\Http\Controllers\Controller;
class PaymentFlowController extends Controller
{
public function index()
{
return view('theme::user.payment-flow.index');
}
public function cartSummary()
{
return view('theme::user.payment-flow.cart-summary');
}
public function paymentSuccess()
{
return view('theme::user.payment-flow.payment-success');
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace Wave\Http\Livewire\Settings;
use Illuminate\Support\Str;
use Livewire\Component;
use Wave\ApiKey;
class Api extends Component
{
// variables for (b)rowing keys
public $keys = [];
// variables for (r)eading/viewing a key
public $readKey;
public $readModal = false;
// variables for (a)dding keys
public $key_name;
// variables for (e)diting keys
public $editKey = '';
public $editModal = false;
// variables for (d)diting keys
public $deleteKey = '';
public $deleteModal = false;
public function mount(){
$this->refreshKeys();
}
protected function rules()
{
return [
'key_name' => 'required',
'editKey.name' => 'required'
];
}
public function readApiModal(ApiKey $key){
$this->readKey = $key;
$this->readModal = true;
}
public function editApiModal(ApiKey $key){
$this->editKey = $key;
$this->editModal = true;
}
public function edit(){
$this->validateOnly('editKey.name');
// For security reasons we need to be sure that the user editing the key name is the owner of the API key
if($this->editKey->user_id != auth()->user()->id){
// Display danger toast notification
$this->dispatchBrowserEvent('popToast', ['type' => 'danger', 'message' => 'Cannot update key name. Invalid User']);
} else {
// Update the key name and display success message
$this->editKey->save();
$this->dispatchBrowserEvent('popToast', ['type' => 'success', 'message' => 'Successfully update API Key name.']);
}
$this->editModal = false;
$this->editKey = null;
$this->refreshKeys();
}
public function add(){
$this->validateOnly('key_name');
$apiKey = auth()->user()->createApiKey(Str::slug($this->key_name));
// Display success toast notification
$this->dispatchBrowserEvent('popToast', ['type' => 'success', 'message' => 'Successfully created new API Key']);
// Clear the API Key name
$this->key_name = '';
$this->refreshKeys();
}
public function deleteApiModal(ApiKey $key){
$this->deleteKey = $key;
$this->deleteModal = true;
}
public function delete(){
// For security reasons we need to make sure that the user deleting the API key is the owner of the API key
if($this->deleteKey->user_id != auth()->user()->id){
// Display danger toast notification
$this->dispatchBrowserEvent('popToast', ['type' => 'danger', 'message' => 'Cannot delete Key. Invalid User']);
} else {
// Delete the API key and show success message
$this->deleteKey->delete();
$this->dispatchBrowserEvent('popToast', ['type' => 'success', 'message' => 'Successfully Deleted API Key']);
}
$this->deleteKey = null;
$this->refreshKeys();
}
public function refreshKeys(){
$this->keys = auth()->user()->apiKeys;
}
public function render()
{
return view('theme::livewire.settings.api');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Wave\Http\Livewire\Settings;
use Livewire\Component;
class Invoices extends Component
{
public function render()
{
return view('theme::livewire.settings.invoices');
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Wave\Http\Livewire\Settings;
use Livewire\Component;
use Wave\Http\Controllers\SubscriptionController;
class Plans extends Component
{
protected $listeners = ['checkout'];
public function checkout($payload){
// Create a new form request to send to the subscription controller
$request = new \Illuminate\Http\Request();
$request->setMethod('POST');
$request->request->add(['checkout_id' => $payload['checkout_id']]);
$subscription = new SubscriptionController;
$checkoutResponse = $subscription->checkout($request);
$this->dispatchBrowserEvent('checkoutCompleteResponse', $checkoutResponse->getData(true) );
}
public function render()
{
return view('theme::livewire.settings.plans');
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Wave\Http\Livewire\Settings;
use Livewire\Component;
class Security extends Component
{
public $current_password;
public $password;
public $password_confirmation;
protected function rules()
{
return [
'current_password' => 'required|current_password',
'password' => 'required|confirmed|min:'.config('wave.auth.min_password_length')
];
}
public function save(){
$this->validate();
auth()->user()->forceFill([
'password' => bcrypt($this->password)
])->save();
// Display success toast notification
$this->dispatchBrowserEvent('popToast', ['type' => 'success', 'message' => 'Successfully updated your password']);
// Clear the input fields
$this->current_password = $this->password = $this->password_confirmation = "";
}
public function render()
{
return view('theme::livewire.settings.security');
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Wave\Http\Livewire\Settings;
use Livewire\Component;
use Wave\Http\Controllers\SubscriptionController;
class Subscription extends Component
{
protected $listeners = ['checkoutCancel'];
public function checkoutCancel($payload){
// Create a new form request to send to the subscription controller
$request = new \Illuminate\Http\Request();
$request->setMethod('POST');
$request->request->add(['id' => $payload['id']]);
$subscription = new SubscriptionController;
$cancelResponse = $subscription->cancel($request);
$this->dispatchBrowserEvent('checkoutCancelResponse', $cancelResponse->getData(true) );
}
public function render()
{
return view('theme::livewire.settings.subscription');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Wave\Http\Middleware;
use Closure;
use TCG\Voyager\Models\Role;
class Cancelled
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if( auth()->user()->role->name == 'cancelled' ){
return redirect()->route('wave.cancelled');
}
return $next($request);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Wave\Http\Middleware;
use Closure;
use Wave\User;
class InstallMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// If there are no users in the database we need to run the install script
if(User::first() === null){
if( $request->route()->getName() != 'wave.install' ){
return redirect()->route('wave.install');
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Wave\Http\Middleware;
use Closure;
//use Illuminate\Support\Facades\Auth;
use Wave\ApiToken;
use Tymon\JWTAuth\Facades\JWTAuth;
use Illuminate\Contracts\Auth\Factory as Auth;
class TokenMiddleware
{
protected $auth;
public function __construct(Auth $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if($request->token && strlen($request->token) <= 60){
$api_token = ApiToken::where('token', '=', $request->token)->first();
if(isset($api_token->id)){
$token = JWTAuth::fromUser($api_token->user);
}
} else {
$this->auth->authenticate();
}
//Then process the next request if every tests passed.
return $next($request);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Wave\Http\Middleware;
use Closure;
class TrialEnded
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if( intval(setting('billing.trial_days', 0)) > 0 && !setting('billing.card_upfront') && auth()->user()->daysLeftOnTrial() < 1 ){
if(auth()->user()->role->name == 'trial' && ($request->route()->getName() != 'wave.trial_over' && $request->route()->getName() != 'wave.settings') ){
return redirect()->route('wave.trial_over');
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Wave\Http\Middleware;
use Closure;
use Wave\User;
use TCG\Voyager\Models\Role;
class WaveMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if(!$this->updateRole()){
if( $request->route()->getName() != 'wave.cancelled' ){
return redirect()->route('wave.cancelled');
}
}
return $next($request);
}
private function updateRole()
{
// if(!auth()->guest() && !auth()->user()->subscribed('main') && !auth()->user()->onTrial() && auth()->user()->role->name != 'admin' && (auth()->user()->subscribed('main') && !auth()->user()->subscription('main')->onGracePeriod()) && auth()->user()->role->name != 'cancelled' ){
// $inactive_user_role = Role::where('name', '=', 'cancelled')->first();
// auth()->user()->role_id = $inactive_user_role->id;
// auth()->user()->save();
// return false;
// }
// if(!auth()->guest() && !auth()->user()->subscribed('main') && auth()->user()->role->name != 'admin' && !auth()->user()->onTrial() && auth()->user()->role->name != 'cancelled'){
// $inactive_user_role = Role::where('name', '=', 'cancelled')->first();
// auth()->user()->role_id = $inactive_user_role->id;
// auth()->user()->save();
// return false;
// }
//return true;
return true;
}
}

31
wave/src/KeyValue.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
class KeyValue extends Model
{
protected $table = 'wave_key_values';
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'type',
'keyvalue_id',
'keyvalue_type',
'key',
'value',
];
public function keyvalue()
{
return $this->morphTo();
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Wave\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class VerifyEmail extends Notification
{
use Queueable;
public $user;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($user)
{
$this->user = $user;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = url('/user/verify/'.$this->user->verification_code);
return (new MailMessage)
->line('Thanks for signing up, but before you can continue we need to verify your email.')
->action('Verify Email', $url)
->line('Thanks! See you soon.');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
class PaddleSubscription extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'subscription_id',
'plan_id',
'user_id',
'status',
'next_bill_date',
'update_url',
'cancel_url',
'cancelled_at',
'last_payment_at',
'next_payment_at',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'cancelled_at' => 'datetime',
'last_payment_at' => 'datetime',
'next_payment_at' => 'datetime',
];
}

17
wave/src/Page.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Facades\Voyager;
class Page extends Model
{
public function link(){
return url('p/' . $this->slug);
}
public function image(){
return Voyager::image($this->image);
}
}

23
wave/src/Plan.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Models\Role;
use Illuminate\Support\Str;
class Plan extends Model
{
public static function boot()
{
parent::boot();
self::creating(function($model){
$model->slug = Str::lower(Str::slug($model->name));
});
}
public function role() {
return $this->belongsTo(Role::class);
}
}

25
wave/src/Post.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
namespace Wave;
use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Facades\Voyager;
class Post extends Model
{
public function link(){
return url('/blog/' . $this->category->slug . '/' . $this->slug);
}
public function user(){
return $this->belongsTo('\Wave\User', 'author_id');
}
public function image(){
return Voyager::image($this->image);
}
public function category(){
return $this->belongsTo('Wave\Category');
}
}

193
wave/src/User.php Normal file
View File

@@ -0,0 +1,193 @@
<?php
namespace Wave;
use Carbon\Carbon;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Lab404\Impersonate\Models\Impersonate;
use TCG\Voyager\Models\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Wave\Announcement;
use Wave\PaddleSubscription;
use Wave\Plan;
class User extends Authenticatable implements JWTSubject
{
use Notifiable, Impersonate;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'username',
'password',
'verification_code',
'verified',
'trial_ends_at',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'trial_ends_at' => 'datetime',
];
public function keyValues()
{
return $this->morphMany('Wave\KeyValue', 'keyvalue');
}
public function keyValue($key)
{
return $this->morphMany('Wave\KeyValue', 'keyvalue')->where('key', '=', $key)->first();
}
public function profile($key)
{
$keyValue = $this->keyValue($key);
return isset($keyValue->value) ? $keyValue->value : '';
}
public function onTrial()
{
if (is_null($this->trial_ends_at)) {
return false;
}
if ($this->subscriber()) {
return false;
}
return true;
}
public function subscribed($plan)
{
$plan = Plan::where('slug', $plan)->first();
// if the user is an admin they automatically have access to the default plan
if (isset($plan->default) && $plan->default && $this->hasRole('admin')) return true;
if (isset($plan->slug) && $this->hasRole($plan->slug)) {
return true;
}
return false;
}
public function subscriber()
{
if ($this->hasRole('admin')) return true;
$roles = $this->roles->pluck('id')->push($this->role_id)->unique();
$plans = Plan::whereIn('role_id', $roles)->count();
// If the user has a role that belongs to a plan
if ($plans) {
return true;
}
return false;
}
public function subscription()
{
return $this->hasOne(PaddleSubscription::class);
}
/**
* @return bool
*/
public function canImpersonate()
{
// If user is admin they can impersonate
return $this->hasRole('admin');
}
/**
* @return bool
*/
public function canBeImpersonated()
{
// Any user that is not an admin can be impersonated
return !$this->hasRole('admin');
}
public function hasAnnouncements()
{
// Get the latest Announcement
$latest_announcement = Announcement::orderBy('created_at', 'DESC')->first();
if (!$latest_announcement) return false;
return !$this->announcements->contains($latest_announcement->id);
}
public function announcements()
{
return $this->belongsToMany('Wave\Announcement');
}
public function createApiKey($name)
{
return ApiKey::create(['user_id' => $this->id, 'name' => $name, 'key' => Str::random(60)]);
}
public function apiKeys()
{
return $this->hasMany('Wave\ApiKey')->orderBy('created_at', 'DESC');
}
public function daysLeftOnTrial()
{
if ($this->trial_ends_at && $this->trial_ends_at >= now()) {
$trial_ends = Carbon::parse($this->trial_ends_at)->addDay();
return $trial_ends->diffInDays(now());
}
return 0;
}
public function avatar()
{
return Storage::url($this->avatar);
}
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}

17
wave/src/Wave.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
namespace Wave;
class Wave
{
public function routes()
{
require __DIR__.'/../routes/web.php';
}
public function api()
{
require __DIR__.'/../routes/api.php';
}
}

View File

@@ -0,0 +1,179 @@
<?php
namespace Wave;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider;
use Wave\Facades\Wave as WaveFacade;
use Wave\TokenGuard;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Blade;
use Livewire\Livewire;
class WaveServiceProvider extends ServiceProvider
{
public function register(){
$loader = AliasLoader::getInstance();
$loader->alias('Wave', WaveFacade::class);
$this->app->singleton('wave', function () {
return new Wave();
});
$this->loadHelpers();
$this->loadLivewireComponents();
$waveMiddleware = [
\Illuminate\Auth\Middleware\Authenticate::class,
\Wave\Http\Middleware\TrialEnded::class,
\Wave\Http\Middleware\Cancelled::class,
];
$this->app->router->aliasMiddleware('token_api', \Wave\Http\Middleware\TokenMiddleware::class);
$this->app->router->pushMiddlewareToGroup('web', \Wave\Http\Middleware\WaveMiddleware::class);
$this->app->router->pushMiddlewareToGroup('web', \Wave\Http\Middleware\InstallMiddleware::class);
$this->app->router->middlewareGroup('wave', $waveMiddleware);
}
public function boot(Router $router, Dispatcher $event){
Relation::morphMap([
'users' => config('wave.user_model')
]);
if(!config('wave.show_docs')){
Gate::define('viewLarecipe', function($user, $documentation) {
return true;
});
}
$this->loadViewsFrom(__DIR__.'/../docs/', 'docs');
$this->loadViewsFrom(__DIR__.'/../resources/views', 'wave');
$this->loadMigrationsFrom(realpath(__DIR__.'/../database/migrations'));
$this->loadBladeDirectives();
}
protected function loadHelpers()
{
foreach (glob(__DIR__.'/Helpers/*.php') as $filename) {
require_once $filename;
}
}
protected function loadMiddleware()
{
foreach (glob(__DIR__.'/Http/Middleware/*.php') as $filename) {
require_once $filename;
}
}
protected function loadBladeDirectives(){
// Subscription Directives
Blade::directive('subscribed', function ($plan) {
return "<?php if (!auth()->guest() && auth()->user()->subscribed($plan)) { ?>";
});
Blade::directive('notsubscribed', function () {
return "<?php } else { ?>";
});
Blade::directive('endsubscribed', function () {
return "<?php } ?>";
});
// Subscriber Directives
Blade::directive('subscriber', function () {
return "<?php if (!auth()->guest() && auth()->user()->subscriber()) { ?>";
});
Blade::directive('notsubscriber', function () {
return "<?php } else { ?>";
});
Blade::directive('endsubscriber', function () {
return "<?php } ?>";
});
// Trial Directives
Blade::directive('trial', function ($plan) {
return "<?php if (!auth()->guest() && auth()->user()->onTrial()) { ?>";
});
Blade::directive('nottrial', function () {
return "<?php } else { ?>";
});
Blade::directive('endtrial', function () {
return "<?php } ?>";
});
// home Directives
Blade::directive('home', function () {
$isHomePage = false;
// check if we are on the homepage
if ( request()->is('/') ) {
$isHomePage = true;
}
return "<?php if ($isHomePage) { ?>";
});
Blade::directive('nothome', function(){
return "<?php } else { ?>";
});
Blade::directive('endhome', function () {
return "<?php } ?>";
});
Blade::directive('waveCheckout', function(){
return '{!! view("wave::checkout")->render() !!}';
});
// role Directives
Blade::directive('role', function ($role) {
return "<?php if (!auth()->guest() && auth()->user()->hasRole($role)) { ?>";
});
Blade::directive('notrole', function () {
return "<?php } else { ?>";
});
Blade::directive('endrole', function () {
return "<?php } ?>";
});
}
private function loadLivewireComponents(){
Livewire::component('wave.settings.security', \Wave\Http\Livewire\Settings\Security::class);
Livewire::component('wave.settings.api', \Wave\Http\Livewire\Settings\Api::class);
Livewire::component('wave.settings.plans', \Wave\Http\Livewire\Settings\Plans::class);
Livewire::component('wave.settings.subscription', \Wave\Http\Livewire\Settings\Subscription::class);
Livewire::component('wave.settings.invoices', \Wave\Http\Livewire\Settings\Invoices::class);
}
}