Major incomplete Change

This commit is contained in:
Omair Saleh
2019-02-14 11:43:19 +08:00
parent 771c52883f
commit 79131671bf
138 changed files with 2345 additions and 69018 deletions
@@ -10,7 +10,7 @@ class ListWarehouses
public function execute(?bool $pagination = false) {
// Get warehouses
$warehouses = $pagination ? Warehouse::all() : Warehouse::orderBy('created_at')->paginate(6) ;
$warehouses = $pagination ? Warehouse::all() : Warehouse::orderBy('created_at')->paginate(10) ;
// Return collection of warehouses as a resource
return WarehouseResource::collection($warehouses);
@@ -0,0 +1,21 @@
<?php
namespace App\Classes\Exceptions\Common;
use Exception;
class ErrorException extends Exception {
/** @var bool */
protected $writeExceptionToLog = true;
/**
* ErrorException constructor.
*
* @param string $message
* @param int $code
*/
public function __construct(string $message, int $code = 0) {
parent::__construct($message, $code);
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Classes\Exceptions\Common;
use App\Models\AbstractModel;
use App\Traits\HandlesPrimaryKeysAsArrays;
class ServiceException extends ErrorException {
use HandlesPrimaryKeysAsArrays;
public function __construct(string $message) {
parent::__construct($message, class_basename($this));
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Modules\Accounts\DataTransferObjects;
class UserInvitationObject
{
/** @var integer */
private $role;
/** @var string */
private $inviteeEmail;
/**
* UserInvitationObject constructor.
* @param int $role
* @param string $inviteeEmail
*/
public function __construct(int $role, string $inviteeEmail)
{
$this->role = $role;
$this->inviteeEmail = $inviteeEmail;
}
/**
* @return int
*/
public function getRole(): int
{
return $this->role;
}
/**
* @return string
*/
public function getInviteeEmail(): string
{
return $this->inviteeEmail;
}
}
@@ -0,0 +1,76 @@
<?php
namespace App\Classes\Modules\Accounts\DataTransferObjects;
final class UserObject {
/** @var string */
private $firstName;
/** @var string */
private $lastName;
/** @var string */
private $email;
/** @var string */
private $password;
/** @var bool */
private $isVerified;
/**
* @param string $firstName
* @param string $lastName
* @param string $email
* @param string $password
* @param bool $isVerified
*/
public function __construct(
string $firstName,
string $lastName,
string $email,
string $password,
bool $isVerified = false
) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->email = $email;
$this->password = $password;
$this->isVerified = $isVerified;
}
/**
* @return string
*/
public function getFirstName(): string {
return $this->firstName;
}
/**
* @return string
*/
public function getLastName(): string {
return $this->lastName;
}
/**
* @return string
*/
public function getEmail(): string {
return $this->email;
}
/**
* @return string
*/
public function getPassword(): string {
return $this->password;
}
/**
* @return bool
*/
public function isVerified(): bool {
return $this->isVerified;
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Classes\Modules\Accounts\Exceptions;
use App\Classes\Exceptions\Common\ErrorException;
final class CannotCreateUserException extends ErrorException {
/**
* @param string $message
*/
public function __construct(string $message) {
parent::__construct($message, __CLASS__);
}
}
@@ -0,0 +1,63 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\Exceptions\Common\ServiceException;
use App\Models\UserEmailVerification;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\MassAssignmentException;
use Illuminate\Database\Eloquent\Model;
class CreatesEmailVerificationAttempt {
private const EMAIL_VERIFICATION_PREFIX = 'EMAIL';
/** @var UserEmailVerification */
private $repository;
/**
* CreatesEmailVerificationForCustomer constructor.
*
* @param UserEmailVerification $repository
*/
public function __construct(UserEmailVerification $repository) {
$this->repository = $repository;
}
/**
* @param string $emailAddress
*
* @throws ServiceException
*
* @return UserEmailVerification|Model
*/
public function execute(string $emailAddress): UserEmailVerification {
// verify if the email address already has a pending verification
$attempts = $this->repository->where('email', $emailAddress)
->where('is_active', true)
->where('is_complete', false);
$attemptExists = count($attempts->get()) > 0 ? true : false;
try {
// if a previous attempt exists, then disable any previous attempts
if ($attemptExists === true) {
$attempts->update(['is_active' => false, 'is_complete' => false]);
}
// generate a token
$token = md5(uniqid(self::EMAIL_VERIFICATION_PREFIX, true) . Carbon::now()->timestamp);
// create the email verification for the customer
return $this->repository->create([
'email' => $emailAddress,
'token' => $token,
'is_complete' => false,
'is_active' => true,
]);
} catch (MassAssignmentException $exception) {
throw new ServiceException($exception->getMessage());
}
}
}
@@ -0,0 +1,67 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\Modules\Accounts\DataTransferObjects\UserObject;
use App\Classes\Modules\Accounts\Exceptions\CannotCreateUserException;
use App\Classes\Modules\ControllerLogic\Exceptions\ResourceConflictException;
use App\Models\User;
use App\Traits\DeterminesIfUserPasswordMatchesRequirements;
use Illuminate\Support\Facades\Hash;
class CreatesUserAccount {
use DeterminesIfUserPasswordMatchesRequirements;
/** @var User */
private $repository;
/** @var CreatesEmailVerificationAttempt */
private $service;
/**
* @param User $repository
* @param CreatesEmailVerificationAttempt $service
*/
public function __construct(
User $repository,
CreatesEmailVerificationAttempt $service
) {
$this->repository = $repository;
$this->service = $service;
}
/**
* @param UserObject $object
*
* @return User
* @throws CannotCreateUserException
*/
public function execute(UserObject $object): ?User {
try {
// verify if the email already exists in the database
if($this->repository->where('email', $object->getEmail())->get()->count()){
throw new ResourceConflictException();
}
/** @var User $user */
$user = $this->repository->create([
'first_name' => $object->getFirstName(),
'last_name' => $object->getLastName(),
'email' => $object->getEmail(),
'password' => Hash::make($object->getPassword())
]);
// create an email verification attempt if needed
if ($object->isVerified() === false) {
$this->service->execute($object->getEmail());
}
return $user;
} catch (\Exception $exception) {
throw new CannotCreateUserException($exception->getMessage());
}
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\common;
use App\Classes\Modules\Accounts\DataTransferObjects\UserInvitationObject;
use App\Classes\Modules\Accounts\Exceptions\InvitationAlreadyExistsException;
use App\Classes\Modules\ControllerLogic\Exceptions\ResourceConflictException;
use App\Models\User;
use App\Models\UserInvitation;
final class CreatesUserInvitation
{
/** @var UserInvitation */
private $repository;
/** @var User */
private $user;
/**
* @param UserInvitation $repository
* @param User $user
*/
public function __construct(UserInvitation $repository, User $user) {
$this->repository = $repository;
$this->user = $user;
}
/**
* @param UserInvitationObject $object
* @return UserInvitation|null
* @throws ResourceConflictException
*/
public function execute(UserInvitationObject $object): ?UserInvitation {
// ensure that there is not already an invitation for the email
$existingInvitations = $this->repository->where('email', $object->getInviteeEmail())->get();
if ($existingInvitations->count() !== 0) {
throw new ResourceConflictException("An existing invitation already exists for the email {$object->getInviteeEmail()}");
}
$model = $this->repository->create([
'email' => $object->getInviteeEmail(),
'hash' => Common::generateRandomHash(50),
'role_id' => $object->getRole(),
'sender_id' => 1,//$this->user->getAuthIdentifier(),
'is_complete' => false,
]);
return $model;
}
}
@@ -0,0 +1,73 @@
<?php
namespace App\Classes\Modules\ControllersLogic\Account;
use App\Classes\Modules\Accounts\DataTransferObjects\UserObject;
use App\Classes\Modules\Accounts\Exceptions\CannotCreateUserException;
use App\Classes\Modules\Accounts\Services\CreatesUserAccount;
use App\Classes\Modules\ControllerLogic\Exceptions\InternalServerErrorException;
use App\Classes\Modules\ControllerLogic\Exceptions\MalformedRequestException;
use App\Classes\ValueObjects\Constants\HttpStatus;
use App\Events\Accounts\UserHasRegistered;
use App\Models\User;
use App\Traits\DeterminesIfUserPasswordMatchesRequirements;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class RegisterAccountLogic
{
use DeterminesIfUserPasswordMatchesRequirements;
/** @var User */
private $repository;
/** @var CreatesUserAccount */
private $createsUserAccount;
/**
* RegisterAccountLogic constructor.
*
* @param User $repository
* @param CreatesUserAccount $createsUserAccount
*/
public function __construct(
User $repository,
CreatesUserAccount $createsUserAccount
) {
$this->repository = $repository;
$this->createsUserAccount = $createsUserAccount;
}
/**
* @param Request $request
* @return JsonResponse
* @throws InternalServerErrorException
* @throws MalformedRequestException
*/
public function execute(Request $request) {
// throws malformed request exception if the password is invalid
if ($this->checkPasswordAndThrowIfInvalid($request->get('password')) === false) {
throw new MalformedRequestException('Password strength is insufficient');
}
try {
// the email doesn't exist in the database, so create the user
$object = new UserObject($request->get('first_name'), $request->get('last_name'),
$request->get('email'), $request->get('password'), false);
$user = $this->createsUserAccount->execute($object);
// dispatch event for user registered
event(new UserHasRegistered($user));
return new JsonResponse(null, HttpStatus::RESOURCE_CREATED);
} catch (CannotCreateUserException $exception) {
throw new InternalServerErrorException("Failed to create user because {$exception->getMessage()}");
}
}
}
@@ -0,0 +1,61 @@
<?php
namespace App\Classes\Modules\ControllersLogic\Account;
use App\Classes\Modules\Accounts\DataTransferObjects\UserInvitationObject;
use App\Classes\Modules\Accounts\Services\CreatesUserInvitation;
use App\Classes\Modules\ControllerLogic\Exceptions\InternalServerErrorException;
use App\Classes\Modules\ControllerLogic\Exceptions\ResourceConflictException;
use App\Classes\ValueObjects\Constants\HttpStatus;
use App\Events\Accounts\UserInvited;
use App\Models\UserInvitation;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class RegistrationInvitationLogic
{
/** @var UserInvitation */
private $repository;
/** @var CreatesUserInvitation */
private $createUserInvitation;
/**
* RegistrationInvitationLogic constructor.
* @param UserInvitation $repository
* @param CreatesUserInvitation $createUserInvitation
*/
public function __construct(
UserInvitation $repository,
CreatesUserInvitation $createUserInvitation
) {
$this->repository = $repository;
$this->createUserInvitation = $createUserInvitation;
}
/**
* @param Request $request
* @return JsonResponse
* @throws InternalServerErrorException
*/
public function execute(Request $request) {
try {
// the email doesn't exist in the database, so create the user
$object = new UserInvitationObject($request->get('role_id'), $request->get('email'));
$invitation = $this->createUserInvitation->execute($object);
// dispatch event for user invited
event(new UserInvited($invitation));
return new JsonResponse(null, HttpStatus::RESOURCE_CREATED);
} catch (ResourceConflictException $exception) {
throw new InternalServerErrorException("Failed to send user invitation because {$exception->getMessage()}");
}
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\ControllersLogic\Companies\AddressBook;
use App\Models\Company;
use App\Http\Resources\AddressBook as AddressBookResource;
class DefaultAddress
{
public function execute( string $companyId, string $id) {
Company::findOrfail($companyId)->addressBook()->update(['default' => 0]);
$address = Company::findOrfail($companyId)->addressBook()->findOrFail($id);
$address->default = 1;
if($address->save()){
return new AddressBookResource($address);
}
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Classes\ControllersLogic\Companies\AddressBook;
use App\Models\Company;
use App\Http\Resources\AddressBook as AddressBookResource;
class DeleteAddress
{
public function execute(string $companyId, string $id) {
// Get address
$address = Company::findOrfail($companyId)->addressBook()->findOrFail($id);
if($address->delete()){
// Return single address as a resource
return new AddressBookResource($address);
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\ControllersLogic\Companies\AddressBook;
use App\Models\Company;
use App\Http\Resources\AddressBook as AddressBookResource;
class ListAddresses
{
public function execute(string $companyId) {
// Get addresses
$addresses = Company::findOrfail($companyId)->addressBook()->orderBy('created_at')->paginate(5);
// Return collection of addresses as a resource
return AddressBookResource::collection($addresses);
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\ControllersLogic\Companies\AddressBook;
use App\Classes\Objects\AddressObject;
use App\Models\AddressBook;
use App\Models\Company;
use App\Http\Resources\AddressBook as AddressBookResource;
class UpdateAddress
{
public function execute(AddressObject $addressObject) {
$address = $addressObject->getId() !== null ? Company::findOrfail($addressObject->getCompanyId())->addressBook()->findOrFail($addressObject->getId()) : new AddressBook;
$address->company_id = $addressObject->getCompanyId();
$address->reference = $addressObject->getReference();
$address->contact = $addressObject->getContact();
$address->street_one = $addressObject->getStreetOne();
$address->street_two = $addressObject->getStreetTwo();
$address->city = $addressObject->getCity();
$address->state = $addressObject->getState();
$address->post_code = $addressObject->getPostCode();
$address->country = $addressObject->getCountry();
if($address->save()){
return new AddressBookResource($address);
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\ControllersLogic\Companies;
use App\Models\Company;
use App\Http\Resources\Company as CompanyResource;
class CompanyProfile
{
public function execute(string $id) {
// Get company
$company = Company::findOrFail($id);
// Return single company as a resource
return new CompanyResource($company);
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\ControllersLogic\Companies;
use App\Classes\Modules\Documents\DeleteAllDocuments;
use App\Models\Company;
use App\Http\Resources\Company as CompanyResource;
use App\Classes\Constants;
class DeleteCompany
{
public function execute(string $id) {
// Get company
$company = Company::findOrFail($id);
foreach (Constants::COMPANY_DOCUMENTS as $documentType) {
(new DeleteAllDocuments(Constants::MODULE_TYPES['company'], $id, $documentType))->execute();
}
if($company->delete()){
// Return single compnay as a resource
return new CompanyResource($company);
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\ControllersLogic\Companies;
use App\Models\Company;
use App\Http\Resources\Company as CompanyResource;
class ListCompanies
{
public function execute() {
// Get company
$companies = Company::orderBy('created_at')->paginate(10);
// Return collection of companies as a resource
return CompanyResource::collection($companies);
}
}
@@ -0,0 +1,45 @@
<?php
namespace App\Classes\ControllersLogic\Companies;
use App\Classes\ControllersLogic\Companies\AddressBook\UpdateAddress;
use App\Classes\Modules\Documents\UpdateDocuments;
use App\Models\Company;
use App\Http\Resources\Company as CompanyResource;
use Illuminate\Http\Request;
use App\Classes\Constants;
class UpdateCompany
{
public function execute(Request $request) {
$company = $request->method() === 'PUT' ? Company::findOrFail($request->input('id')) : new company;
$company->fill($request->except(array_merge(Constants::COMPANY_DOCUMENTS, Constants::ADDRESS_FIELDS)));
if($company->save()){
foreach (Constants::COMPANY_DOCUMENTS as $documentType){
$documents = $request->input($documentType);
if($documents !== null){
(new updateDocuments(
Constants::MODULE_TYPES['company'],
$company->id,
$documentType))->execute($documents);
}
}
(new UpdateAddress())->execute($request, $company->id, false, true);
return new CompanyResource($company);
}
}
public function updateDocuments(){
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Classes\ControllersLogic\Contacts;
use App\Models\Contact;
use App\Http\Resources\Contact as ContactResource;
class DeleteContact
{
public function execute(string $id) {
// Get address
$contact= Contact::findOrFail($id);
if($contact->delete()){
// Return single address as a resource
return new ContactResource($contact);
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\ControllersLogic\Contacts;
use App\Models\Contact;
use App\Http\Resources\Contact as ContactResource;
class ListContacts
{
public function execute(int $type, string $reference) {
// Get contacts
$contacts = Contact::where('type', $type)->where('reference_id', $reference)->orderBy('created_at')->paginate(5);
// Return collection of contacts as a resource
return ContactResource::collection($contacts);
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Classes\ControllersLogic\Contacts;
use App\Models\Contact;
use App\Http\Resources\Contact as ContactResource;
use Illuminate\Http\Request;
class UpdateContact
{
public function execute(Request $request, int $type, string $reference) {
$contact = $request->method() === 'PUT' ? Contact::findOrFail($request->input('id')) : new Contact;
$contact->type = $type;
$contact->reference_id = $reference;
$contact->name = $request->input('name');
$contact->designation = $request->input('designation');
$contact->contact = $request->input('contact');
$contact->email = $request->input('email');
if($contact->save()){
return new ContactResource($contact);
}
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class AccessForbiddenException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'A forbidden attempt to access protected resources was detected',
HttpStatus::ACCESS_FORBIDDEN);
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class AccessUnauthorisedException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'An unauthorised attempt to access protected resources was detected',
HttpStatus::ACCESS_UNAUTHORISED);
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class InternalServerErrorException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'An internal server error has occurred. Please check application logs for more information.',
HttpStatus::SERVER_ERROR);
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class MalformedRequestException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'Unable to process the request as it is malformed', HttpStatus::BAD_REQUEST);
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class ResourceConflictException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'Unable to create the requested resource as it already exists',
HttpStatus::RESOURCE_ALREADY_EXISTS);
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class ResourceNotFoundException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'Unable to find the requested resource', HttpStatus::RESOURCE_NOT_FOUND);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\Modules\ControllerLogic\Exceptions;
use App\Classes\Exceptions\Common\ErrorException;
abstract class ServiceApiException extends ErrorException {
/** @var int */
private $httpStatusCode;
public function __construct(string $message, int $httpStatusCode = 500) {
parent::__construct($message, $httpStatusCode);
$this->httpStatusCode = $httpStatusCode;
}
/**
* @return int
*/
public function getHttpStatusCode(): int {
return $this->httpStatusCode;
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Classes\ControllersLogic\Orders;
use App\Classes\Constants;
use App\Classes\Modules\Orders\Steps\GenerateOrderSteps;
use App\Classes\Modules\Steps\ModularStep;
use App\Models\Order;
use Illuminate\Http\Request;
class CreateOrder
{
public function execute(String $companyId, Request $request){
$order = new Order;
$order->company_id = $companyId;
$order->warehouse_id = $request->input('warehouse_id');
$order->marking = $request->input('marking');
$order->current_step = Constants::ORDER_PROCESSING_STEP;
if($order->save()){
// Generate Order Steps
$modularStep = new ModularStep();
$orderSteps = (new GenerateOrderSteps([$modularStep->warehouseModule($order->warehouse_id !== null)]))->getSteps()->toArray();
$order->orderSteps()->createMany($orderSteps);
// confirm order
return (new UpdateOrderStep())->execute($order->id, $request);
}
return false;
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Classes\ControllersLogic\Orders;
use App\Classes\Modules\Orders\Steps\OrderStepUpdate;
use Illuminate\Http\Request;
class UpdateOrderStep
{
public function execute(String $orderId, Request $request){
return (new OrderStepUpdate($orderId))->execute($request);
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Classes\ControllersLogic\Warehouses;
use App\Models\Warehouse;
use App\Http\Resources\Warehouse as WarehouseResource;
class DeleteWarehouse
{
public function execute(string $id) {
// Get warehouse
$warehouse = Warehouse::findOrFail($id);
if($warehouse->delete()){
// Return single warehouse as a resource
return new WarehouseResource($warehouse);
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\ControllersLogic\Warehouses;
use App\Models\Warehouse;
use App\Http\Resources\Warehouse as WarehouseResource;
class ListWarehouses
{
public function execute(?bool $pagination = false) {
// Get warehouses
$warehouses = $pagination ? Warehouse::all() : Warehouse::orderBy('created_at')->paginate(6) ;
// Return collection of warehouses as a resource
return WarehouseResource::collection($warehouses);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\ControllersLogic\Warehouses;
use App\Models\Warehouse;
use App\Http\Resources\Warehouse as WarehouseResource;
use Illuminate\Http\Request;
class UpdateWarehouse
{
public function execute(Request $request) {
$warehouse = $request->method() === 'PUT' ? Warehouse::findOrFail($request->input('id')) : new Warehouse;
$warehouse->fill($request->except('id'));
if($warehouse->save()){
return new WarehouseResource($warehouse);
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\ControllersLogic\Warehouses;
use App\Models\Warehouse;
use App\Http\Resources\Warehouse as WarehouseResource;
class WarehouseProfile
{
public function execute(string $id) {
// Get warehouse
$warehouse = Warehouse::findOrFail($id);
// Return single warehouse as a resource
return new WarehouseResource($warehouse);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class HttpStatus {
public const OK_WITH_MESSAGE = 200;
public const RESOURCE_CREATED = 201;
public const REQUEST_ACCEPTED = 202;
public const OK = 204;
public const BAD_REQUEST = 400;
public const ACCESS_UNAUTHORISED = 401;
public const ACCESS_FORBIDDEN = 403;
public const RESOURCE_NOT_FOUND = 404;
public const METHOD_NOT_FOUND = 405;
public const RESOURCE_ALREADY_EXISTS = 409;
public const VALIDATION_FAILED = 422;
public const SERVER_ERROR = 500;
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class UserRoles {
public const SUPER_ADMIN = 0;
public const ADMIN = 1;
public const IMPORTER = 2;
public const WAREHOUSE = 3;
public const SUPPLIER = 4;
}
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace App\Classes;
final class common
{
/**
* @param int $length
* @return string
*/
public static function generateRandomHash(int $length = 10): string {
return substr(bin2hex(ceil($length / 2)), 0, $length);
}
}
+6
View File
@@ -0,0 +1,6 @@
<?php
namespace App\Events\Accounts;
interface UserEvent {
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Events\Accounts;
use App\Models\User;
use Illuminate\Queue\SerializesModels;
class UserHasRegistered implements UserEvent {
use SerializesModels;
/** @var User */
private $user;
/**
* @param User $user
*/
public function __construct(User $user) {
$this->user = $user;
}
/**
* @return User
*/
public function getUser(): User {
return $this->user;
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace App\Events\Accounts;
use App\Models\UserInvitation;
use Illuminate\Queue\SerializesModels;
class UserInvited implements UserEvent {
use SerializesModels;
/** @var UserInvitation */
private $invitation;
/**
* @param UserInvitation $invitation
*/
public function __construct(UserInvitation $invitation) {
$this->invitation = $invitation;
}
/**
* @return UserInvitation
*/
public function getInvitation(): UserInvitation
{
return $this->invitation;
}
}
@@ -1,31 +0,0 @@
<?php
namespace App\Http\Controllers\Account;
use App\Classes\Modules\ControllerLogic\Account\RetrieveUserProfileLogic;
use App\Classes\Modules\ControllerLogic\Account\UpdateUserProfileLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AccountController extends Controller
{
/**
* @param int|null $id
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function index(?int $id = null){
return (new RetrieveUserProfileLogic($id))->execute();
}
/**
* @param Request $request
*
* @return int
* @internal param int|null $id
*
*/
public function update(Request $request): int {
return (new UpdateUserProfileLogic($request->get('id') ?: null))->execute($request->except('id'));
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Account;
use App\Classes\Modules\ControllersLogic\Account\RegistrationInvitationLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class InviteUserController extends Controller
{
public function invite(Request $request, RegistrationInvitationLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Account;
use App\Classes\Modules\ControllersLogic\Account\RegisterAccountLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class RegisterAccountController extends Controller
{
/**
* @param Request $request
* @param RegisterAccountLogic $logic
* @return JsonResponse
* @throws \App\Classes\Modules\ControllerLogic\Exceptions\InternalServerErrorException
* @throws \App\Classes\Modules\ControllerLogic\Exceptions\MalformedRequestException
*/
public function register(Request $request, RegisterAccountLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
-5
View File
@@ -6,11 +6,6 @@ use Closure;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Artisan;
/**
* @copyright Copyright (C) 2018 IP ServerOne Solutions Sdn. Bhd. All rights reserved.
* @author Zhe Yang, Lee <zylee@ipserverone.com>
* @license Proprietary
*/
class ClearCache {
/** @var Application */
private $application;
@@ -0,0 +1,34 @@
<?php
namespace App\Listeners\Accounts;
use App\Events\Accounts\UserEvent;
use App\Events\Accounts\UserHasRegistered;
use App\Events\Accounts\UserInvited;
use App\Models\UserEmailVerification;
use App\Notifications\InvitationEmail;
use App\Notifications\VerifyEmail;
class UserEventHandler {
/**
* @param UserEvent $event
*/
public function handle(UserEvent $event): void {
if ($event instanceof UserHasRegistered) {
$attempts = UserEmailVerification::where('email', $event->getUser()->email);
if ($attempts !== null && !$event->getUser()->hasVerifiedEmail()) {
$event->getUser()->notify(new VerifyEmail($attempts->first()));
$attempts->first()->update(['is_sent' => true]);
}
}
if ($event instanceof UserInvited) {
$event->getInvitation()->notify(new InvitationEmail($event));
}
}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
abstract class AbstractModel extends Model {
use LogsActivity;
protected static $logFillable = true;
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Activitylog\Traits\LogsActivity;
abstract class AbstractUserModel extends Authenticatable {
use LogsActivity;
protected static $logFillable = true;
}
+1 -8
View File
@@ -2,21 +2,14 @@
namespace App\models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class AddressBook extends Model
class AddressBook extends AbstractModel
{
use LogsActivity;
protected $table = 'address_book';
protected $fillable = [
'company_id', 'reference', 'contact', 'street_one', 'street_two', 'city', 'state', 'post_code', 'country', 'default'
];
protected static $logFillable = true;
public function company()
{
return $this->belongsTo('App\Models\Company');
+1 -8
View File
@@ -2,22 +2,15 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class Company extends Model
class Company extends AbstractModel
{
use LogsActivity;
protected $table = 'companies';
protected $fillable = [
'marking', 'name', 'email', 'registration_no', 'tax_no'
];
protected static $logFillable = true;
public function addressBook()
{
return $this->hasMany('App\Models\AddressBook');
+1 -6
View File
@@ -2,13 +2,10 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Classes\Constants;
use Spatie\Activitylog\Traits\LogsActivity;
class Contact extends Model
class Contact extends AbstractModel
{
use LogsActivity;
protected $table = 'contacts';
@@ -16,8 +13,6 @@ class Contact extends Model
'type', 'reference_id', 'name', 'designation', 'contact', 'email'
];
protected static $logFillable = true;
public function companyContacts($query)
{
return $query->where('type', Constants::MODULE_TYPES['company']);
+1 -8
View File
@@ -2,22 +2,15 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class CustomIssues extends Model
class CustomIssues extends AbstractModel
{
use LogsActivity;
protected $table = 'custom_issues';
protected $fillable = [
'schedule_id', 'remark'
];
protected static $logFillable = true;
public function shippingSchedule()
{
return $this->belongsTo(ShippingSchedule::class, 'schedule_id');
+1 -7
View File
@@ -2,19 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class Document extends Model
class Document extends AbstractModel
{
use LogsActivity;
protected $table = 'documents';
protected $fillable = [
'type', 'reference_id', 'document_type', 'name', 'primary'
];
protected static $logFillable = true;
}
+1 -8
View File
@@ -2,21 +2,14 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class Order extends Model
class Order extends AbstractModel
{
use LogsActivity;
protected $table = 'orders';
protected $fillable = [
'company_id', 'marking', 'forwarder_id', 'supplier_id', 'warehouse_id', 'current_step', 'complete'
];
protected static $logFillable = true;
public function orderSteps()
{
return $this->hasMany(OrderStep::class, 'order_id');
+1 -8
View File
@@ -2,22 +2,15 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class OrderStep extends Model
class OrderStep extends AbstractModel
{
use LogsActivity;
protected $table = 'order_steps';
protected $fillable = [
'order_id', 'reference_id', 'primary', 'sequence', 'complete'
];
protected static $logFillable = true;
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
+1 -8
View File
@@ -2,22 +2,15 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class Package extends Model
class Package extends AbstractModel
{
use LogsActivity;
protected $table = 'packages';
protected $fillable = [
'list_id', 'description', 'width', 'length', 'height', 'quantity'
];
protected static $logFillable = true;
public function packingList()
{
return $this->belongsTo(PackingList::class, 'list_id');
+1 -7
View File
@@ -2,22 +2,16 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class PackingList extends Model
class PackingList extends AbstractModel
{
use LogsActivity;
protected $table = 'packing_lists';
protected $fillable = [
'order_id', 'reference_no', 'confirmed'
];
protected static $logFillable = true;
public function packages()
{
return $this->hasMany(Package::class, 'list_id');
-5
View File
@@ -3,21 +3,16 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class ReceiveNote extends Model
{
use LogsActivity;
protected $table = 'receive_notes';
protected $fillable = [
'order_id', 'tracking_no', 'receive_date'
];
protected static $logFillable = true;
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
+1 -8
View File
@@ -2,22 +2,15 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class ShippingArrangement extends Model
class ShippingArrangement extends AbstractModel
{
use LogsActivity;
protected $table = 'shipping_arrangements';
protected $fillable = [
'order_id', 'container_no', 'seal_no'
];
protected static $logFillable = true;
public function shippingSchedule()
{
return $this->hasMany(ShippingSchedule::class, 'arrangement_id');
+1 -7
View File
@@ -2,22 +2,16 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class ShippingSchedule extends Model
class ShippingSchedule extends AbstractModel
{
use LogsActivity;
protected $table = 'shipping_schedules';
protected $fillable = [
'arrangement_id', 'ETD', 'ETA', 'status'
];
protected static $logFillable = true;
public function shippingArrangement()
{
return $this->belongsTo(ShippingArrangement::class, 'arrangement_id');
+12 -8
View File
@@ -2,15 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Activitylog\Traits\LogsActivity;
class User extends Authenticatable
class User extends AbstractUserModel
{
use Notifiable;
// use LogsActivity;
/**
* The attributes that are mass assignable.
@@ -18,11 +15,9 @@ class User extends Authenticatable
* @var array
*/
protected $fillable = [
'first_name', 'last_name', 'email', 'password', 'verified',
'first_name', 'last_name', 'email', 'password', 'verified', 'role'
];
// protected static $logFillable = true;
/**
* The attributes that should be hidden for arrays.
*
@@ -31,4 +26,13 @@ class User extends Authenticatable
protected $hidden = [
'password', 'remember_token',
];
/**
* @return HasMany
*/
public function pendingEmailVerifications(): HasMany {
return $this->hasMany(UserEmailVerification::class, 'email')
->where('is_active', true)
->where('is_complete', false);
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @copyright Copyright (C) 2018 IP ServerOne Solutions Sdn. Bhd. All rights reserved.
* @author Zhe Yang, Lee <zylee@ipserverone.com>
* @license Proprietary
*/
final class UserEmailVerification extends AbstractModel {
public $incrementing = true;
protected $table = 'user_email_verification';
protected $fillable = [
'email',
'token',
'is_complete',
'is_active',
'is_sent'
];
/**
* @return BelongsTo
*/
public function user(): BelongsTo {
return $this->belongsTo(user::class, 'email');
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Notifications\Notifiable;
class UserInvitation extends AbstractModel
{
use Notifiable;
public $incrementing = true;
protected $table = 'user_invitation';
protected $fillable = [
'email',
'hash',
'role_id',
'sender_id',
'is_complete',
];
public function sender() {
return $this->belongsTo(user::class, 'sender_id');
}}
+1 -7
View File
@@ -2,19 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
class Warehouse extends Model
class Warehouse extends AbstractModel
{
use LogsActivity;
protected $table = 'warehouses';
protected $fillable = [
'name', 'email', 'street_one', 'street_two', 'city', 'state', 'post_code', 'country'
];
protected static $logFillable = true;
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notification;
class AbstractEmail extends Notification
{
public function via()
{
return 'mail';
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Notifications;
use App\Events\Accounts\UserInvited;
use Illuminate\Notifications\Messages\MailMessage;
class InvitationEmail extends AbstractEmail
{
/** @var UserInvited */
private $invitation;
/**
* InvitationEmail constructor.
* @param UserInvited $invitationt
*/
public function __construct(UserInvited $invitation) {
$this->invitation = $invitation;
}
public function toMail()
{
return (new MailMessage)
->subject('Registration Invite')
->line($this->senderName().' has sent you an invitation to create an account with us.')
->action('Create Account', $this->invitationUrl());
}
private function invitationUrl(){
return url(route('auth.registration', ['hash' => $this->invitation->getInvitation()->hash]));
}
private function senderName(){
$sender = $this->invitation->getInvitation()->sender;
return $sender->first_name.' '.$sender->last_name;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace App\Notifications;
use App\Models\UserEmailVerification;
use Illuminate\Notifications\Messages\MailMessage;
class VerifyEmail extends AbstractEmail
{
/** @var UserEmailVerification */
private $attempt;
/**
* EmailVerificationRequest constructor.
*
* @param UserEmailVerification $attempt
*/
public function __construct(UserEmailVerification $attempt) {
$this->attempt = $attempt;
}
public function toMail()
{
return (new MailMessage)
->subject('Email Verification Required')
->line('Please click the button below to verify your email address.')
->action('Verify Email Address', $this->verificationUrl()
)
->line('If you did not create an account, no further action is required.');
}
private function verificationUrl(){
return $this->attempt->token;
}
}
+4 -23
View File
@@ -2,33 +2,14 @@
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use App\Events\Accounts\UserEvent;
use App\Listeners\Accounts\UserEventHandler;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
/** @var array */
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
UserEvent::class => [UserEventHandler::class]
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
//
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Traits;
trait DeterminesIfUserPasswordMatchesRequirements {
/**
* @param string $password
*
* @return bool
*/
private function doesPasswordMeetRequirements(string $password): bool {
$matches = [];
preg_match('/^.*(?=.{3,})(?=.*[a-z])(?=.*[A-Z])(?=.*[\d]).*$/', $password, $matches);
return count($matches) > 0;
}
/**
* @param string $password
*
* @return bool
*/
private function checkPasswordAndThrowIfInvalid(string $password): bool {
return $this->doesPasswordMeetRequirements($password) === true;
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
trait HandlesPrimaryKeysAsArrays {
/**
* @param Model $model
*
* @return array
*/
private function getPrimaryKeys(Model $model): array {
return (array) $model->getKeyName();
}
/**
* @param Model $model
*
* @return string
*/
private function getPrimaryKeyValuesAsString(Model $model): string {
return implode(', ', array_map(function ($keyName) use ($model) {
return $model->getAttribute($keyName);
}, $this->getPrimaryKeys($model)));
}
}
+1 -6
View File
@@ -8,11 +8,6 @@ $factory->define(App\Models\Company::class, function (Faker $faker) {
'marking' => 'CIEF/'.$faker->numerify('###').$faker->regexify('[A-Z]{3}'),
'email' => $faker->companyEmail,
'registration_no' => $faker->numerify('######-W'),
'tax_no' => $faker->numerify('KMTAX####'),
'street_one' => $faker->streetAddress,
'city' => $faker->city,
'state' => $faker->city,
'post_code' => $faker->postcode,
'country' => $faker->country
'tax_no' => $faker->numerify('KMTAX####')
];
});
@@ -1,5 +1,6 @@
<?php
use App\Classes\ValueObjects\Constants\UserRoles;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
@@ -24,17 +25,29 @@ class CreateUserTable extends Migration
$table->string('email')->unique();
$table->string('password');
$table->integer('verified')->nullable()->default(0);
$table->integer('role_id');
$table->rememberToken();
$table->timestamps();
});
DB::table('users')->insert(
[
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'email' => env('EMAIL_DEVELOPMENT', 'admin@cief.com'),
'first_name' => 'Omair',
'last_name' => 'Saleh',
'email' => env('EMAIL_DEVELOPMENT', 'omair@izyim.com'),
'password' => Hash::make('123456abcabc'),
'verified' => 1,
'role_id' => UserRoles::SUPER_ADMIN,
'created_at' => \Carbon\Carbon::now(),
'updated_at' => \Carbon\Carbon::now()
],
[
'first_name' => 'Development',
'last_name' => 'User',
'email' => env('EMAIL_DEVELOPMENT', 'dev@izyim.com'),
'password' => Hash::make('123456abcabc'),
'verified' => 1,
'role_id' => UserRoles::ADMIN,
'created_at' => \Carbon\Carbon::now(),
'updated_at' => \Carbon\Carbon::now()
]
@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserEmailVerificationTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_email_verification', function (Blueprint $table) {
$table->increments('id');
$table->string('email', 100);
$table->string('token', 32);
$table->boolean('is_complete')->default(false);
$table->boolean('is_active');
$table->boolean('is_sent')->default(false);
$table->timestamps();
$table->foreign('email')->references('email')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_email_verification');
}
}
@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserInvitationTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_invitation', function (Blueprint $table) {
$table->increments('id');
$table->string('email', 100)->unique();
$table->string('hash', 50);
$table->integer('role_id');
$table->integer('sender_id')->unsigned()->index();
$table->boolean('is_complete')->default(false);
$table->timestamps();
$table->foreign('sender_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_invitation');
}
}
+4 -4
View File
@@ -11,10 +11,10 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void {
if(app()->environment() !== "production"){
//$this->call(CompaniesTableSeeder::class);
//$this->call(AddressBookTableSeeder::class);
//$this->call(ContactsTableSeeder::class);
//$this->call(WarehousesTableSeeder::class);
$this->call(CompaniesTableSeeder::class);
$this->call(AddressBookTableSeeder::class);
$this->call(ContactsTableSeeder::class);
$this->call(WarehousesTableSeeder::class);
}
$this->call(PrimaryStepsTableSeeder::class);
-4
View File
@@ -20,7 +20,6 @@
"desandro-classie": "^1.0.1",
"dialog-fx": "^0.0.2",
"epic-spinners": "^1.0.3",
"feather-icons": "^4.5.0",
"font-awesome": "^4.7.0",
"gulp-cli": "^2.0.1",
"imagesloaded": "^4.1.4",
@@ -39,7 +38,6 @@
"select2": "^4.0.6-rc.1",
"sweetalert": "^2.1.0",
"switchery-npm": "^0.8.2",
"tether": "^1.4.3",
"trumbowyg": "^2.9.4",
"twitter-bootstrap-wizard": "^1.2.0",
"typeahead.js": "^0.11.1",
@@ -88,8 +86,6 @@
"vendorJs": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery-ui-dist/jquery-ui.min.js",
"./node_modules/feather-icons/dist/feather.min.js",
"./node_modules/tether/dist/js/tether.min.js",
"./node_modules/popper.js/dist/umd/popper.min.js",
"./node_modules/bootstrap/dist/js/bootstrap.min.js",
"./node_modules/jquery-unveil/jquery.unveil.js",
+6
View File
File diff suppressed because one or more lines are too long
-19142
View File
File diff suppressed because it is too large Load Diff
-27
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 89 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Some files were not shown because too many files have changed in this diff Show More