Commit eb83816b by Ali

Initial commit

parents
module.exports = {
servers: {
one: {
// TODO: set host address, username, and authentication method
host: '176.31.196.89',
username: 'ubuntu'
}
},
app: {
// TODO: change app name and path
name: 'jibc_st',
path: '../../',
servers: {
one: {},
},
buildOptions: {
serverOnly: true
},
env: {
// TODO: Change to your app's url
// If you are using ssl, it needs to start with https://
"ROOT_URL": "https://jibc-stage-api.vqode.com",
"NODE_ENV": "production",
"MAIL_URL": "smtp://postmaster%40mail.vqode.com:VQode1234@smtp.mailgun.org:587",
"MONGO_URL": "mongodb://vqode:vqodePass123@176.31.196.91:10005/admin?retryWrites=true"
},
docker: {
// change to 'abernix/meteord:base' if your app is using Meteor 1.4 - 1.5
image: 'abernix/meteord:node-8.15.1-base',
prepareBundle: true,
// buildInstructions: [
// ]
},
// Show progress bar while uploading bundle to server
// You might need to disable it on CI servers
enableUploadProgressBar: true
},
// mongo: {
// version: '3.4.1',
// servers: {
// one: {}
// }
// },
// (Optional)
// Use the proxy to setup ssl or to route requests to the correct
// app when there are several apps
proxy: {
domains: 'jibc-stage-api.vqode.com',
ssl: {
// Enable Let's Encrypt
letsEncryptEmail: 'email@aliarshad.info'
}
}
};
This diff is collapsed. Click to expand it.
.idea
node_modules
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.
notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2
1.2.0-standard-minifiers-package
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes
1.3.0-split-minifiers-package
1.4.0-remove-old-dev-bundle-link
1.4.1-add-shell-server-package
1.4.3-split-account-service-packages
1.5-add-dynamic-import-package
1.7-split-underscore-from-meteor-base
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
PcGyM96Gv0b1.5QY8brmXZySs
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-base@1.4.0 # Packages every Meteor app needs to have
mobile-experience@1.0.5 # Packages for a great mobile UX
mongo@1.6.2 # The database Meteor supports right now
reactive-var@1.0.11 # Reactive variable for tracker
tracker@1.2.0 # Meteor's client-side reactive programming library
standard-minifier-css@1.5.3 # CSS minifier run for production mode
standard-minifier-js@2.4.1 # JS minifier run for production mode
es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
ecmascript@0.12.4 # Enable ECMAScript2015+ syntax in app code
shell-server@0.4.0 # Server-side component of the `meteor shell` command
barbatus:typescript
server-render
reywood:publish-composite
accounts-password
dburles:collection-helpers
ostrio:files
tunguska:reactive-aggregate
server
browser
METEOR@1.8.1
accounts-base@1.4.4
accounts-password@1.5.1
allow-deny@1.1.0
autoupdate@1.6.0
babel-compiler@7.3.4
babel-runtime@1.3.0
barbatus:typescript@0.7.0
barbatus:typescript-compiler@0.10.0
barbatus:typescript-runtime@1.1.0
base64@1.0.12
binary-heap@1.0.11
boilerplate-generator@1.6.0
callback-hook@1.1.0
check@1.3.1
dburles:collection-helpers@1.1.0
ddp@1.4.0
ddp-client@2.3.3
ddp-common@1.4.0
ddp-rate-limiter@1.0.7
ddp-server@2.3.0
diff-sequence@1.1.1
dynamic-import@0.5.1
ecmascript@0.12.7
ecmascript-runtime@0.7.0
ecmascript-runtime-client@0.8.0
ecmascript-runtime-server@0.7.1
ejson@1.1.0
email@1.2.3
es5-shim@4.8.0
fetch@0.1.1
geojson-utils@1.0.10
hot-code-push@1.0.4
http@1.4.2
id-map@1.1.0
inter-process-messaging@0.1.0
launch-screen@1.1.1
livedata@1.0.18
localstorage@1.2.0
logging@1.1.20
meteor@1.9.3
meteor-base@1.4.0
minifier-css@1.4.2
minifier-js@2.4.1
minimongo@1.4.5
mobile-experience@1.0.5
mobile-status-bar@1.0.14
modern-browsers@0.1.4
modules@0.13.0
modules-runtime@0.10.3
mongo@1.6.3
mongo-decimal@0.1.1
mongo-dev-server@1.1.0
mongo-id@1.0.7
npm-bcrypt@0.9.3
npm-mongo@3.1.2
ordered-dict@1.1.0
ostrio:cookies@2.4.1
ostrio:files@1.12.2
promise@0.11.2
random@1.1.0
rate-limit@1.0.9
reactive-var@1.0.11
reload@1.3.0
retry@1.1.0
reywood:publish-composite@1.7.2
routepolicy@1.1.0
server-render@0.3.1
service-configuration@1.0.11
sha@1.0.9
shell-server@0.4.0
socket-stream-client@0.2.2
srp@1.0.12
standard-minifier-css@1.5.3
standard-minifier-js@2.4.1
tracker@1.2.0
tunguska:reactive-aggregate@1.2.1
underscore@1.0.10
url@1.2.0
webapp@1.7.4
webapp-hashing@1.0.9
# JIBC-Meteor-API
### Build Status
### Setup
- Install / Update node modules.
- `meteor npm i`
### Serve
- Serve webapp.
- `npm start`
declare module '*';
declare module 'meteor/ostrio:files' {
import { Mongo } from 'meteor/mongo';
import { ReactiveVar } from 'meteor/reactive-var';
import { Observable } from 'rxjs';
class FileObj {
size: number;
name: string;
type: string;
path: string;
isVideo: boolean;
isAudio: boolean;
isImage: boolean;
isText: boolean;
isJSON: boolean;
isPDF: boolean;
extension?: string;
_storagePath: string;
_downloadRoute: string;
_collectionName: string;
public?: boolean;
meta?: Object;
userid?: string;
updatedAt?: Date;
versions: Object;
}
type FileRef = any; // File record from Mongo DB... don't know the details yet
interface FileData {
size: number;
type: string;
mime: string;
"mime-type": string;
ext: string;
extension: string;
name: string;
}
interface FilesCollectionConfig {
storagePath?: string;
collection?: Mongo.Collection<any>;
collectionName?: string;
continueUploadTTL?: string;
ddp?: Object;
cacheControl?: string;
responseHeaders?: { [x: string]: string } | ((responseCode?, fileRef?, versionRef?, version?) => { [x: string]: string });
throttle?: number | boolean;
downloadRoute?: string;
schema?: Object;
chunkSize?: number;
namingFunction?: () => string;
permissions?: number;
parentDirPermissions?: number;
integrityCheck?: boolean;
strict?: boolean;
downloadCallback?: (fileObj: FileObj) => boolean;
protected?: boolean | ((fileObj: FileObj) => boolean | number);
public?: boolean;
onBeforeUpload?: (fileData: FileData) => boolean | string;
onBeforeRemove?: (cursor: Mongo.Cursor<any>) => boolean;
onInitiateUpload?: (fileData: FileData) => void;
onAfterUpload?: (fileRef: FileRef) => any;
onAfterRemove?: (files: Object[]) => any;
onbeforeunloadMessage?: string | (() => string);
allowClientCode?: boolean;
debug?: boolean;
interceptDownload?: (http: any, fileRef: any, version: string) => boolean;
}
export interface SearchOptions {
sort?: Mongo.SortSpecifier;
skip?: number;
limit?: number;
fields?: Mongo.FieldSpecifier;
reactive?: boolean;
transform?: Function;
}
export interface InsertOptions {
file: File | Object | string;
isBase64?: boolean;
meta?: { [x: string]: any };
transport?: 'ddp' | 'http'
onStart?: (error: Object, fileData: Object) => any;
onUploaded?: (error: Object, fileData: Object) => any;
onAbort?: (fileData: Object) => any;
onError?: (error: Object, fileData: Object) => any;
onProgress?: (progress: number, fileData: Object) => any;
onBeforeUpload?: (fileData: Object) => any;
streams?: number | 'dynamic';
chunkSize?: number | 'dynamic';
allowWebWorkers?: boolean;
}
export interface LoadOptions {
fileName: string;
meta?: Object;
type?: string;
size?: number;
}
export class FileUpload {
file: File;
onPause: ReactiveVar<boolean>;
progress: ReactiveVar<number>;
estimateTime: ReactiveVar<number>;
estimateSpeed: ReactiveVar<number>;
state: ReactiveVar<'active' | 'paused' | 'aborted' | 'completed'>;
pause();
continue();
toggle();
pipe();
start();
on(event: string, callback: Function): any;
}
export class FileCursor extends FileObj { // Is it correct to say that it extends FileObj?
remove(callback: (err) => void): void;
link(): string;
get(property: string): Object | any;
fetch(): Object[];
with(): ReactiveVar<FileCursor>;
}
export class FilesCursor extends Mongo.Cursor<FileObj> {
cursor: Mongo.Cursor<FileObj>; // Refers to base cursor? Why is this existing?
get(): Object[];
hasNext(): boolean;
next(): Object;
hasPrevious(): boolean;
previous(): Object;
first(): Object;
last(): Object;
remove(callback: (err) => void): void;
each(): FileCursor[];
current(): Object | undefined;
}
export class FilesCollection {
collection: Mongo.Collection<FileObj>;
schema: any;
constructor(config: FilesCollectionConfig)
find(selector?: Mongo.Selector, options?: SearchOptions): FilesCursor;
findOne(selector?: Mongo.Selector, options?: SearchOptions): FileCursor;
insert(settings: InsertOptions, autoStart?: boolean): FileUpload;
remove(select: Mongo.Selector, callback: (error) => any): FilesCollection;
update(selector: Mongo.Selector | Mongo.ObjectID | string, modifier: Mongo.Modifier, options?: {
multi?: boolean;
upsert?: boolean;
}): Observable<number>;
link(fileRef: FileRef, version?: string): string;
allow(options: Mongo.AllowDenyOptions): void;
deny(options: Mongo.AllowDenyOptions): void;
denyClient(): void;
on(event: string, callback: (fileRef: FileRef) => void): FilesCursor;
unlink(fileRef: FileRef, version?: string): FilesCollection;
addFile(path: string, opts: LoadOptions, callback: (err: any, fileRef: FileRef) => any, proceedAfterUpload: boolean);
load(url: string, opts: LoadOptions, callback: (err: any, fileRef: FileRef) => any, proceedAfterUpload: boolean);
write(buffer: Buffer, opts: LoadOptions, callback: (err: any, fileRef: FileRef) => any, proceedAfterUpload: boolean);
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "jibc-meteor-api",
"version": "0.0.1",
"scripts": {
"start": "meteor run",
"lint": "tslint -c tslint.json server/**/*.ts",
"fastlint": "git diff --cached --name-only | grep .ts$ | xargs -L1 \"./node_modules/.bin/tslint\" -c tslint.json --fix"
},
"private": true,
"dependencies": {
"@babel/runtime": "7.6.2",
"@nguniversal/module-map-ngfactory-loader": "8.1.1",
"aws-sdk": "^2.550.0",
"core-js": "2.6.5",
"meteor-client-bundler": "^0.5.1",
"meteor-node-stubs": "^0.4.1",
"meteor-rxjs": "^0.4.14",
"rxjs": "^6.0.0",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@types/meteor": "1.4.14",
"@types/node": "~8.9.4",
"angular-tslint-rules": "^1.20.1",
"codelyzer": "~5.2.0",
"pre-commit": "^1.2.2",
"protractor": "~5.4.0",
"ts-loader": "^5.2.0",
"ts-node": "~7.0.0",
"tslint": "~5.20.0",
"tslint-config-airbnb": "^5.11.2",
"typescript": "3.5.3",
"webpack-cli": "^3.1.0"
},
"pre-commit": [
"fastlint"
]
}
import { Meteor } from 'meteor/meteor';
import { Roles } from './collections/role';
import { PERMISSIONS } from './config';
export const seedDB = async () => {
// tslint:disable-next-line:ban-ts-ignore
// @ts-ignore
const allPermissions = Object.values(PERMISSIONS);
try {
if (!Roles.find({})
.fetch().length || Roles.find({})
.fetch().length === 0) {
// Roles
await Promise.all([
Roles.insert({
Title: 'Admin',
Permissions: allPermissions,
Description: '',
}).toPromise(),
Roles.insert({
Title: 'Blocked',
Permissions: [],
Description: '',
}).toPromise(),
]);
} else {
// Update Roles Permissions
await Promise.all([
Roles
.update({ Title: 'Admin' }, { $set: { Permissions: allPermissions } })
.toPromise(),
]);
}
if (!Meteor.users.find({})
.fetch().length && Meteor.users.find({})
.fetch().length === 0) {
Accounts.createUser({
username: 'admin',
password: 'admin',
email: 'ali.arshad@vqode.com',
profile: {
Role: Roles.findOne({ Title: 'Admin' })._id, // admin role id
FirstName: 'Admin',
LastName: 'User',
Status: 'ACTIVE',
},
});
}
} catch (e) {
throw new Meteor.Error('Error while seeding database.');
}
};
/* tslint:disable:no-require-imports */
// tslint:disable-next-line:import-name
import S3 from 'aws-sdk/clients/s3';
import { FilesCollection } from 'meteor/ostrio:files';
import '../env';
const allowedExt = ['mp3', 'png', 'jpg', 'jpeg', 'gif'];
let s3Client;
let s3Conf;
let sendToStorage;
let interceptDownload;
let fileDir = './';
const bound = Meteor.bindEnvironment((callback) => {
return callback();
});
if (Meteor.isServer) {
const fs = require('fs');
const path = require('path');
const stream = require('stream');
const os = require('os');
fileDir = os.tmpdir();
s3Conf = JSON.parse(process.env.S3);
s3Client = new S3({
secretAccessKey: s3Conf.secret,
accessKeyId: s3Conf.key,
region: s3Conf.region,
sslEnabled: false,
httpOptions: {
timeout: 6000,
},
});
sendToStorage = (fileRef) => {
const filePath = path.join(s3Conf.path, fileRef._id + fileRef.extensionWithDot);
s3Client.putObject(
{
StorageClass: 'STANDARD',
Bucket: s3Conf.bucket,
Key: filePath,
Body: fs.createReadStream(fileRef.path),
ContentType: fileRef.type,
},
(error) => {
bound(() => {
if (error) {
// console.error(error);
} else {
files.update({ _id: fileRef._id }, { $set: { uploadedToS3: true } });
if (fs.existsSync(fileRef.path)) {
fs.unlink(fileRef.path);
}
}
});
});
};
interceptDownload = function (http, fileRef, version): boolean {
const filePath = path.join(s3Conf.path, fileRef._id + fileRef.extensionWithDot);
if (!fileRef.uploadedToS3) {
return false;
}
const opts = {
Bucket: s3Conf.bucket,
Key: filePath,
Range: '',
};
if (http.request.headers.range) {
const vRef = fileRef.versions[version];
const range = JSON.parse(JSON.stringify(http.request.headers.range));
const array = range.split(/bytes=([0-9]*)-([0-9]*)/);
const start = parseInt(array[1], 10);
let end = parseInt(array[2], 10);
if (isNaN(end)) {
// Request data from AWS:S3 by small chunks
end = (start + this.chunkSize) - 1;
if (end >= vRef.size) {
end = vRef.size - 1;
}
}
opts.Range = `bytes=${start}-${end}`;
http.request.headers.range = `bytes=${start}-${end}`;
}
s3Client.getObject(opts, (error, data) => {
if (error) {
// console.error(error);
if (!http.response.finished) {
http.response.end();
}
} else {
if (http.request.headers.range && data.httpResponse && data.httpResponse.headers['content-range']) {
// Set proper range header in according to what is returned from AWS:S3
http.request.headers.range = data.httpResponse.headers['content-range'].split('/')[0]
.replace('bytes ', 'bytes=');
}
const dataStream = new stream.PassThrough();
this.serve(http, fileRef, fileRef.versions[version], version, dataStream);
dataStream.end(data.Body);
}
});
return true;
};
}
const onBeforeUpload = (fileRef) => {
if (allowedExt.indexOf(fileRef.ext) === -1) {
return `Only ${allowedExt.join(', ')} files are allowed.`;
}
if (fileRef.size <= 1024 * 1024 * 128) {
return true;
}
return 'Max. file size allowed is 50MB';
};
const onAfterUpload = (fileRef) => {
if (Meteor.isServer) {
sendToStorage(fileRef);
}
};
export const files = new FilesCollection({
onBeforeUpload,
onAfterUpload,
interceptDownload,
collectionName: 'files',
storagePath: fileDir,
allowClientCode: true,
});
if (Meteor.isServer) {
files.denyClient();
}
if (Meteor.isClient) {
Meteor.subscribe('files.images.all');
}
if (Meteor.isServer) {
Meteor.publish('files.images.all', () => files.collection.find({}));
}
import { MongoObservable } from 'meteor-rxjs';
import { Role } from '../models/role';
// tslint:disable-next-line:variable-name
export const Roles = new MongoObservable.Collection<Role>('roles');
export const PERMISSIONS = {
CAN_LOGIN: 'CAN_LOGIN',
UPDATE_ROLE: 'UPDATE_ROLE',
CAN_UPDATE_OWN_USER: 'CAN_UPDATE_OWN_USER',
CAN_UPDATE_USER: 'CAN_UPDATE_USER',
CAN_SEE_ALL_USERS: 'CAN_SEE_ALL_USERS',
CAN_ACCESS_DASHBOARD_PAGE: 'CAN_ACCESS_DASHBOARD_PAGE',
};
process.env.S3 = '{"path": "files", "key":"AKIAWEWXPEPGGRRUHLH4","secret":"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","bucket":"siingio","region":"us-east-1"}';
process.env.MAIL_URL = 'smtp://postmaster%40mail.vqode.com:VQode1234@smtp.mailgun.org:587';
import { Meteor } from 'meteor/meteor';
import { seedDB } from './app.seeding';
import { PERMISSIONS } from './config';
import { User } from './models/user';
import { UtilsService } from './services/utils.service';
Meteor.startup(() => {
const seed = true;
if (seed) {
seedDB();
}
// Validate Login Attempt
Accounts.validateLoginAttempt((data): boolean => {
const user: User = data.user;
return user && user.profile.Role && UtilsService.hasPermissionOfUser(user, PERMISSIONS.CAN_LOGIN);
});
// Changing url of reset password
Accounts.emailTemplates.resetPassword.text = (user, url) => {
const token = url.substring(url.lastIndexOf('/') + 1, url.length);
return Meteor.absoluteUrl(`auth/reset-password/${token}`);
};
});
import { Meteor } from 'meteor/meteor';
import { first } from 'rxjs/operators';
import { Roles } from '../collections/role';
import { PERMISSIONS } from '../config';
import { Role } from '../models/role';
import { UtilsService } from '../services/utils.service';
Meteor.methods({
async saveRole(role: Role): Promise<void> {
try {
if (role._id && UtilsService.hasPermission(PERMISSIONS.UPDATE_ROLE)) {
await Roles.update(role._id, role)
.pipe(first())
.toPromise();
}
} catch (e) {
throw new Meteor.Error('Unable to add.', JSON.stringify(e));
}
},
});
import { Meteor } from 'meteor/meteor';
import { Roles } from '../collections/role';
import { PERMISSIONS } from '../config';
import { User } from '../models/user';
import { UtilsService } from '../services/utils.service';
import { Query } from '../models/query';
Meteor.methods({
usersGetCount(query: Query): any {
return {
recordsFiltered: Meteor.users.find(query.query).count(),
recordsTotal: Meteor.users.find().count(),
};
},
registerUser(usr: any): string {
const role = Roles.findOne({ Slug: usr.Role });
if (role) {
if (!Accounts.findUserByEmail(usr.Email)) {
const user: User = {
email: usr.Email,
password: usr.Password,
username: usr.Email,
profile: {
FirstName: usr.FirstName,
LastName: usr.LastName,
Role: role._id,
OriginalRole: role._id,
Status: usr.Status,
},
};
const createdUserId = Accounts.createUser(user);
return createdUserId;
}
throw new Meteor.Error(422, 'Email address already in use.');
}
throw new Meteor.Error(403, 'Not Enough Permissions');
},
updateUser(user: User): any {
if (!UtilsService.hasPermission(PERMISSIONS.CAN_UPDATE_OWN_USER)) {
throw new Meteor.Error(403, 'Forbidden.');
}
if (user._id) {
const updateObj = { $set: { profile: user.profile } };
if (user.profile.Email) {
updateObj.$set['emails.0.address'] = user.profile.Email;
}
return Meteor.users.update(user._id, updateObj);
}
},
disableUser(user: User): any {
if (UtilsService.hasPermission(PERMISSIONS.CAN_UPDATE_USER)) {
const disableRole = Roles.findOne({ Title: 'Blocked' });
const usr = Meteor.users.findOne(user._id);
usr.profile.Role = disableRole._id;
return Meteor.users.update(user._id, usr);
}
throw new Meteor.Error(403, 'Not enough permissions');
},
checkUserByEmail(email: string): User {
return Accounts.findUserByEmail(email);
},
async enableUser(user: User): Promise<any> {
if (UtilsService.hasPermission(PERMISSIONS.CAN_UPDATE_USER)) {
const role = Roles.findOne({ Slug: user.profile.OriginalRole });
const usr = Meteor.users.findOne(user._id);
usr.profile.Role = role._id;
return Meteor.users.update(user._id, usr);
}
throw new Meteor.Error(403, 'Not enough permissions');
},
});
export class Query {
constructor(
public query = {} as any,
public options: QueryOptions = new QueryOptions(),
) {
}
}
export class QueryOptions {
sort?: Mongo.SortSpecifier;
skip?: number;
limit?: number;
fields?: Mongo.FieldSpecifier;
reactive?: boolean;
transform?: Function;
constructor() {
this.skip = 0;
this.limit = 10;
}
}
export interface Role {
_id?: string;
Title: string;
Permissions: string[];
Description: string;
}
import { Role } from './role';
export interface User {
_id?: string;
emails?: Meteor.UserEmail[];
email?: string;
password?: string;
username?: string;
profile?: UserProfile;
Role?: any;
OldPassword?: string;
NewPassword?: string;
ConfirmNewPassword?: string;
}
export interface UserProfile {
FirstName?: string;
LastName?: string;
Role?: string;
OriginalRole?: string;
RoleTitle?: string;
RoleObj?: Role;
AccountActiveUntil?: Date;
Phone?: string;
Address?: string;
Email?: string;
Password?: string;
Status?: 'ACTIVE' | 'DISABLED';
}
import { Meteor } from 'meteor/meteor';
import { Roles } from '../collections/role';
Meteor.publish('roles', () => Roles.find({}));
import { Meteor } from 'meteor/meteor';
// tslint:disable-next-line:ban-ts-ignore
// @ts-ignore
import { publishComposite } from 'meteor/reywood:publish-composite';
import { PERMISSIONS } from '../config';
import { Query } from '../models/query';
import { UtilsService } from '../services/utils.service';
import { Roles } from '../collections/role';
publishComposite('usersList', (filters = {}) => {
const queryFilters = { ...new Query(), ...filters };
if (!UtilsService.hasPermission([PERMISSIONS.CAN_SEE_ALL_USERS])) {
throw new Meteor.Error(403, 'Not enough permissions to get all users');
}
return {
find(): any {
return Meteor.users.find(queryFilters.query, { ...queryFilters.options });
},
children: [
{
find(user): any {
return Roles.find({ _id: user.profile.Role });
},
},
],
};
});
// tslint:disable-next-line:no-require-imports import-name
import AWS = require('aws-sdk');
import { Meteor } from 'meteor/meteor';
import { Observable, Subject } from 'rxjs';
import { Roles } from '../collections/role';
import { User } from '../models/user';
export class UtilsService {
static getLoggedInUserPermissions(): string[] {
const usr: User = Meteor.user();
const role = Roles.findOne(usr.profile.Role);
return role.Permissions;
}
static hasPermission(permissions: string | string[]): boolean {
const usr: User = Meteor.user();
if (usr) {
const role = Roles.findOne(usr.profile.Role);
if (typeof permissions === 'string') {
return role.Permissions.indexOf(permissions) !== -1;
}
return permissions.every(p => role.Permissions.indexOf(p) !== -1);
}
return false;
}
static hasPermissionOfUser(user: User, permission: string): boolean {
const role = Roles.findOne(user.profile.Role);
return role.Permissions.indexOf(permission) !== -1;
}
static uploadToAWS(base64, key): Observable<any> {
AWS.config.update({
accessKeyId: 'AKIAIKEPLM32K6ZXO2WQ',
secretAccessKey: '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',
signatureVersion: 'v4',
});
const s3 = new AWS.S3();
const subject = new Subject();
const base64Data = new Buffer(base64.replace(/^data:image\/\w+;base64,/, ''), 'base64');
// With this setup, each time your users uploads an image, will be overwritten.
// To prevent this, use a unique Key each time.
// This won't be needed if they're uploading their avatar, hence the filename, userAvatar.js.
const params = {
Bucket: 'vqode-tracker',
Key: key, // type is not required
Body: base64Data,
ACL: 'public-read',
ContentEncoding: 'base64', // required
ContentLength: Buffer.byteLength(base64Data),
ContentType: 'image/jpeg', // required. Notice the back ticks
};
// The upload() is used instead of putObject() as we'd need the location url and
// assign that to our users profile/database
// see: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
s3.upload(params, Meteor.bindEnvironment((err, data): any => {
if (err) {
subject.error(err);
subject.complete();
// tslint:disable-next-line:no-console
return console.log(err);
}
subject.next(data);
subject.complete();
// Continue if no error
// Save data.Location in your database
}));
return subject.asObservable();
}
}
declare module '*/package.json' {
const name: string;
}
import assert from 'assert';
describe('angular-cli-meteor', function () {
it('package.json has correct name', async function () {
const { name } = await import('../package.json');
assert.strictEqual(name, 'angular-cli-meteor');
});
it('server is not client', function () {
assert.strictEqual(Meteor.isClient, false);
});
});
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"module": "commonjs",
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
],
"types": [
"@types/meteor"
]
}
}
{
"extends": "tslint-config-airbnb",
"rules": {
"no-console": true
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment