Compare commits

..

3 Commits

Author SHA1 Message Date
a.bouhuolia
3ceb9adda2 fix(server): sending invite email 2023-05-05 00:28:57 +02:00
a.bouhuolia
4d44ce4c7f fix(webapp): some flag icons are missing 2023-05-04 21:29:12 +02:00
a.bouhuolia
903dc0522a chore: add CONTRIBUTING.md file 2023-04-27 01:56:46 +02:00
268 changed files with 64 additions and 4453 deletions

View File

@@ -34,7 +34,7 @@ Contributions via pull requests are much appreciated. Once the approach is agree
## Contribute to Backend ## Contribute to Backend
- Clone the `bigcapital` repository and `cd` into `bigcapital` directory. - Clone the `bigcapital` repository and `cd` into `bigcapital` directory.
- Install all npm dependencies of the monorepo, you don't have to change directory to the `backend` package. just hit the command on root directory and it will install dependencies of all packages. - Install all npm dependencies of the monorepo, you don't have to change directory to the `backend` package. just hit these command on root directory and it will install dependencies of all packages.
``` ```
npm install npm install
@@ -47,7 +47,7 @@ npm run bootstrap
docker-compose up -d docker-compose up -d
``` ```
Wait some seconds, and hit `docker-compose ps` to see the result and you should see the same result below. Wait some seconds, and hit `docker-compose ps` and you should see the same result below.
``` ```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
@@ -122,7 +122,7 @@ There are many other ways to get involved with the community and to participate
- Use the product, submitting GitHub issues when a problem is found. - Use the product, submitting GitHub issues when a problem is found.
- Help code review pull requests and participate in issue threads. - Help code review pull requests and participate in issue threads.
- Submit a new feature request as an issue. - Submit a new feature request as an issue.
- Help answer questions on forums such as Stack Overflow and SigNoz Community Slack Channel. - Help answer questions on forums such as Bigcapital Community Discord Channel.
- Tell others about the project on Twitter, your blog, etc. - Tell others about the project on Twitter, your blog, etc.
**[`^top^`](#)** **[`^top^`](#)**

View File

@@ -4,6 +4,7 @@ import moment from 'moment';
global.__root_dir = path.join(__dirname, '..'); global.__root_dir = path.join(__dirname, '..');
global.__resources_dir = path.join(global.__root_dir, 'resources'); global.__resources_dir = path.join(global.__root_dir, 'resources');
global.__locales_dir = path.join(global.__resources_dir, 'locales'); global.__locales_dir = path.join(global.__resources_dir, 'locales');
global.__views_dir = path.join(global.__root_dir, 'views');
moment.prototype.toMySqlDateTime = function () { moment.prototype.toMySqlDateTime = function () {
return this.format('YYYY-MM-DD HH:mm:ss'); return this.format('YYYY-MM-DD HH:mm:ss');

View File

@@ -1,6 +1,7 @@
import { AnyObject } from '@casl/ability/dist/types/types'; import { AnyObject } from '@casl/ability/dist/types/types';
import { ITenant } from '@/interfaces'; import { ITenant } from '@/interfaces';
import { Model } from 'objection'; import { Model } from 'objection';
import { Tenant } from '@/system/models';
export interface ISystemUser extends Model { export interface ISystemUser extends Model {
id: number; id: number;
@@ -54,20 +55,52 @@ export interface IUserInvite {
export interface IInviteUserService { export interface IInviteUserService {
acceptInvite(token: string, inviteUserInput: IInviteUserInput): Promise<void>; acceptInvite(token: string, inviteUserInput: IInviteUserInput): Promise<void>;
/**
* Re-send user invite.
* @param {number} tenantId -
* @param {string} email -
* @return {Promise<{ invite: IUserInvite }>}
*/
resendInvite( resendInvite(
tenantId: number, tenantId: number,
userId: number, userId: number,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<{ ): Promise<{
invite: IUserInvite; user: ITenantUser;
}>; }>;
/**
* Sends invite mail to the given email from the given tenant and user.
* @param {number} tenantId -
* @param {string} email -
* @param {IUser} authorizedUser -
* @return {Promise<IUserInvite>}
*/
sendInvite( sendInvite(
tenantId: number, tenantId: number,
email: string, sendInviteDTO: IUserSendInviteDTO,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<{ ): Promise<{
invite: IUserInvite; invitedUser: ITenantUser;
}>; }>;
}
export interface IAcceptInviteUserService {
/**
* Accept the received invite.
* @param {string} token
* @param {IInviteUserInput} inviteUserInput
* @throws {ServiceErrors}
* @returns {Promise<void>}
*/
acceptInvite(token: string, inviteUserDTO: IInviteUserInput): Promise<void>;
/**
* Validate the given invite token.
* @param {string} token - the given token string.
* @throws {ServiceError}
*/
checkInvite( checkInvite(
token: string token: string
): Promise<{ inviteToken: IUserInvite; orgName: object }>; ): Promise<{ inviteToken: IUserInvite; orgName: object }>;
@@ -121,7 +154,7 @@ export interface IUserInvitedEventPayload {
tenantId: number; tenantId: number;
user: ITenantUser; user: ITenantUser;
} }
export interface IUserInviteTenantSyncedEventPayload{ export interface IUserInviteTenantSyncedEventPayload {
invite: IUserInvite; invite: IUserInvite;
authorizedUser: ISystemUser; authorizedUser: ISystemUser;
tenantId: number; tenantId: number;
@@ -143,7 +176,7 @@ export interface IAcceptInviteEventPayload {
export interface ICheckInviteEventPayload { export interface ICheckInviteEventPayload {
inviteToken: IUserInvite; inviteToken: IUserInvite;
tenant: ITenant tenant: Tenant;
} }
export interface IUserSendInviteDTO { export interface IUserSendInviteDTO {

View File

@@ -1,5 +1,6 @@
import { Container, Inject } from 'typedi'; import { Container, Inject } from 'typedi';
import InviteUserService from '@/services/InviteUsers/AcceptInviteUser'; import InviteUserService from '@/services/InviteUsers/AcceptInviteUser';
import SendInviteUsersMailMessage from '@/services/InviteUsers/SendInviteUsersMailMessage';
export default class UserInviteMailJob { export default class UserInviteMailJob {
/** /**
@@ -21,24 +22,17 @@ export default class UserInviteMailJob {
*/ */
public async handler(job, done: Function): Promise<void> { public async handler(job, done: Function): Promise<void> {
const { invite, authorizedUser, tenantId } = job.attrs.data; const { invite, authorizedUser, tenantId } = job.attrs.data;
const sendInviteMailMessage = Container.get(SendInviteUsersMailMessage);
const Logger = Container.get('logger');
const inviteUsersService = Container.get(InviteUserService);
Logger.info(`Send invite user mail - started: ${job.attrs.data}`);
try { try {
await inviteUsersService.mailMessages.sendInviteMail( await sendInviteMailMessage.sendInviteMail(
tenantId, tenantId,
authorizedUser, authorizedUser,
invite invite
); );
Logger.info(`Send invite user mail - finished: ${job.attrs.data}`);
done(); done();
} catch (error) { } catch (error) {
Logger.info( console.log(error);
`Send invite user mail - error: ${job.attrs.data}, error: ${error}`
);
done(error); done(error);
} }
} }

View File

@@ -109,7 +109,7 @@ export default class Mail {
* Retrieve view content from the view directory. * Retrieve view content from the view directory.
*/ */
private getViewContent(): string { private getViewContent(): string {
const filePath = path.join(global.__root_dir, `../views/${this.view}`); const filePath = path.join(global.__views_dir, `/${this.view}`);
return fs.readFileSync(filePath, 'utf8'); return fs.readFileSync(filePath, 'utf8');
} }
} }

View File

@@ -22,7 +22,7 @@ import SaleInvoiceAutoIncrementSubscriber from '@/subscribers/SaleInvoices/AutoI
import SaleInvoiceConvertFromEstimateSubscriber from '@/subscribers/SaleInvoices/ConvertFromEstimate'; import SaleInvoiceConvertFromEstimateSubscriber from '@/subscribers/SaleInvoices/ConvertFromEstimate';
import PaymentReceiveAutoSerialSubscriber from '@/subscribers/PaymentReceive/AutoSerialIncrement'; import PaymentReceiveAutoSerialSubscriber from '@/subscribers/PaymentReceive/AutoSerialIncrement';
import SyncSystemSendInvite from '@/services/InviteUsers/SyncSystemSendInvite'; import SyncSystemSendInvite from '@/services/InviteUsers/SyncSystemSendInvite';
import InviteSendMainNotification from '@/services/InviteUsers/InviteSendMailNotification'; import InviteSendMainNotification from '@/services/InviteUsers/InviteSendMailNotificationSubscribe';
import SyncTenantAcceptInvite from '@/services/InviteUsers/SyncTenantAcceptInvite'; import SyncTenantAcceptInvite from '@/services/InviteUsers/SyncTenantAcceptInvite';
import SyncTenantUserMutate from '@/services/Users/SyncTenantUserSaved'; import SyncTenantUserMutate from '@/services/Users/SyncTenantUserSaved';
import { SyncTenantUserDelete } from '@/services/Users/SyncTenantUserDeleted'; import { SyncTenantUserDelete } from '@/services/Users/SyncTenantUserDeleted';

View File

@@ -12,9 +12,12 @@ import {
} from '@/interfaces'; } from '@/interfaces';
import { ERRORS } from './constants'; import { ERRORS } from './constants';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { IAcceptInviteUserService } from '@/interfaces';
@Service() @Service()
export default class AcceptInviteUserService { export default class AcceptInviteUserService
implements IAcceptInviteUserService
{
@Inject() @Inject()
private eventPublisher: EventPublisher; private eventPublisher: EventPublisher;

View File

@@ -1,7 +1,4 @@
import { import { IUserInviteTenantSyncedEventPayload } from '@/interfaces';
IUserInvitedEventPayload,
IUserInviteTenantSyncedEventPayload,
} from '@/interfaces';
import events from '@/subscribers/events'; import events from '@/subscribers/events';
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';

View File

@@ -1,12 +1,12 @@
import path from 'path';
import { ISystemUser } from '@/interfaces'; import { ISystemUser } from '@/interfaces';
import TenancyService from '@/services/Tenancy/TenancyService';
import Mail from '@/lib/Mail'; import Mail from '@/lib/Mail';
import { Service, Container } from 'typedi'; import { Service } from 'typedi';
import config from '@/config';
import { Tenant } from '@/system/models'; import { Tenant } from '@/system/models';
import config from '@/config';
@Service() @Service()
export default class InviteUsersMailMessages { export default class SendInviteUsersMailMessage {
/** /**
* Sends invite mail to the given email. * Sends invite mail to the given email.
* @param user * @param user
@@ -18,7 +18,7 @@ export default class InviteUsersMailMessages {
.findById(tenantId) .findById(tenantId)
.withGraphFetched('metadata'); .withGraphFetched('metadata');
const root = __dirname + '/../../../views/images/bigcapital.png'; const root = path.join(global.__views_dir, '/images/bigcapital.png');
const mail = new Mail() const mail = new Mail()
.setSubject(`${fromUser.firstName} has invited you to join a Bigcapital`) .setSubject(`${fromUser.firstName} has invited you to join a Bigcapital`)

View File

@@ -8,7 +8,7 @@ import { IAcceptInviteEventPayload } from '@/interfaces';
@Service() @Service()
export default class SyncTenantAcceptInvite { export default class SyncTenantAcceptInvite {
@Inject() @Inject()
tenancy: HasTenancyService; private tenancy: HasTenancyService;
/** /**
* Attaches events with handlers. * Attaches events with handlers.

View File

@@ -74,17 +74,15 @@ export default class InviteTenantUserService implements IInviteUserService {
/** /**
* Re-send user invite. * Re-send user invite.
* @param {number} tenantId - * @param {number} tenantId -
* @param {string} email - * @param {string} email -
* @return {Promise<{ invite: IUserInvite }>} * @return {Promise<{ invite: IUserInvite }>}
*/ */
public async resendInvite( public async resendInvite(
tenantId: number, tenantId: number,
userId: number, userId: number,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<{ ): Promise<{ user: ITenantUser }> {
user: ITenantUser;
}> {
// Retrieve the user by id or throw not found service error. // Retrieve the user by id or throw not found service error.
const user = await this.getUserByIdOrThrowError(tenantId, userId); const user = await this.getUserByIdOrThrowError(tenantId, userId);

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

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