Guest User

Untitled

a guest
Oct 24th, 2018
1,478
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.52 KB | None | 0 0
  1. // The following is a snippet of JS extracted from a variety of components built out for a recent vue.js project.
  2. // Followed by a few endpoints found in the corresponding API.
  3.  
  4. // Crypto.js
  5. import { mapState } from 'vuex';
  6. import { validationMixin } from 'vuelidate';
  7. import { required } from 'vuelidate/lib/validators';
  8. import { general } from '@/utils';
  9. import VueQrcode from '@xkeshi/vue-qrcode';
  10. import CreateBtsAccount from './CreateBtsAccount';
  11. import AddBtsAccount from './AddBtsAccount';
  12.  
  13. export default {
  14.  
  15. components: { qrcode: VueQrcode, CreateBtsAccount, AddBtsAccount },
  16.  
  17. mixins: [validationMixin, general],
  18.  
  19. props: {
  20. open: Boolean,
  21. token: Object,
  22. },
  23.  
  24. data: () => ({
  25. active: 'bitcoin',
  26. tabs: ['bitcoin', 'bitcoincash', 'ethereum', 'litecoin', 'bitshares'],
  27. currencies: {
  28. bitcoin: {
  29. title: 'BTC',
  30. address: null,
  31. },
  32. bitcoincash: {
  33. title: 'BCC',
  34. address: null,
  35. },
  36. ethereum: {
  37. title: 'ETH',
  38. address: null,
  39. },
  40. litecoin: {
  41. title: 'LTC',
  42. address: null,
  43. },
  44. },
  45. page: 1,
  46. codeOptions: {
  47. size: 200,
  48. backgroundAlpha: 0,
  49. },
  50. accountname: null,
  51. title: null,
  52. description: null,
  53. address: null,
  54. loading: true,
  55. adding: false,
  56. creating: false,
  57. }),
  58.  
  59. methods: {
  60. postBitsharesAccount() {
  61. this.$store.dispatch('bitshares/postBitsharesAccount', {
  62. accountname: this.accountname,
  63. title: this.title,
  64. description: this.description,
  65. });
  66. },
  67. setAddresses(data) {
  68. const keys = Object.keys(data);
  69. for (let i = 0; i < keys.length; i += 1) {
  70. this.currencies[keys[i]].address = data[keys[i]];
  71. }
  72. this.loading = false;
  73. },
  74. },
  75.  
  76. watch: {
  77. open(val) {
  78. this.loading = true;
  79. if (!this.token) return null;
  80. const { name } = this.token;
  81. if (!this.addresses[name]) {
  82. this.$store.dispatch('crypto/getAddresses', this.token)
  83. .then(({ data }) => {
  84. this.setAddresses(data);
  85. }).catch(() => {
  86. this.loading = false;
  87. });
  88. } else {
  89. this.setAddresses(this.addresses[name]);
  90. }
  91. return val;
  92. },
  93. },
  94. computed: {
  95. ...mapState({
  96. bitshares: ({ bitshares }) => !!bitshares.accounts.filter(acct => !!acct.verified).length,
  97. addresses: ({ crypto }) => crypto.addresses,
  98. }),
  99. step: {
  100. get() {
  101. return this.bitshares ? 2 : this.page;
  102. },
  103. set(val) {
  104. this.page = val;
  105. },
  106. },
  107. accountErrors() {
  108. const errors = [];
  109. if (!this.$v.accountname.$dirty) return errors;
  110. !this.$v.accountname.noSpace && errors.push('Account Name cannot contain white spaces');
  111. !this.$v.accountname.required && errors.push('Account Name is required');
  112. !this.$v.accountname.isUnique && errors.push('This account name is taken');
  113. !this.$v.accountname.isBitshares && errors.push('This account name is not in bitshares');
  114. return errors;
  115. },
  116. titleErrors() {
  117. const errors = [];
  118. if (!this.$v.title.$dirty) return errors;
  119. !this.$v.title.required && errors.push('Title is required');
  120. return errors;
  121. },
  122. },
  123. validations: {
  124. accountname: {
  125. required,
  126. isBitshares(value) {
  127. if (value === '') return true;
  128. if (this.bitsharesaccountajax) {
  129. this.bitsharesaccountajax.abort();
  130. }
  131. this.bitsharesaccountajax = $.ajax({
  132. url: `api/bitshares/bitshares_accounts/${value}`,
  133. success: result => result,
  134. });
  135. return this.bitsharesaccountajax;
  136. },
  137. isUnique(value) {
  138. if (value === '') return true;
  139. if (this.uniqueaccountajax) {
  140. this.uniqueaccountajax.abort();
  141. }
  142. this.uniqueaccountajax = $.ajax({
  143. url: `api/bitshares/duplicates/${value}`,
  144. success: result => result,
  145. });
  146. return this.uniqueaccountajax;
  147. },
  148. noSpace(value) {
  149. return !/\s/g.test(value);
  150. },
  151. },
  152. description: { required },
  153. title: { required },
  154. },
  155. };
  156.  
  157. // Payment.js
  158. import { mapState, mapGetters } from 'vuex';
  159. import { math } from '@/utils';
  160. export default {
  161. props: {
  162. open: Boolean,
  163. id: Number,
  164. },
  165. mixins: [math],
  166. data: () => ({
  167. loading: false,
  168. passing: false,
  169. failing: false,
  170. delivering: false,
  171. deliverLoading: false,
  172. details: null,
  173. headers: [
  174. { align: 'left', value: 'status' },
  175. { align: 'right', value: 'date' },
  176. { align: 'right', value: 'details' },
  177. ],
  178. }),
  179. watch: {
  180. id(id) {
  181. this.loading = true;
  182. this.$store.dispatch('accounts/getPayment', id)
  183. .then(() => {
  184. this.loading = false;
  185. });
  186. },
  187. },
  188. methods: {
  189. dispute() {
  190. console.log('Disputing');
  191. },
  192. capitalize(value) {
  193. if (!value) return '';
  194. value = value.toString();
  195. return value.charAt(0).toUpperCase() + value.slice(1);
  196. },
  197. passPayment() {
  198. if (this.pass === 'delivery') {
  199. this.delivering = true;
  200. } else {
  201. this.passing = true;
  202. this.update({ id: this.payment.id, action: this.pass })
  203. .then(() => this.$store.dispatch('accounts/getPayment', this.payment.id))
  204. .then(() => { this.passing = false; })
  205. .catch(() => { this.passing = false; });
  206. }
  207. },
  208. failPayment() {
  209. this.failing = true;
  210. this.update({ id: this.payment.id, action: this.fail })
  211. .then(() => this.$store.dispatch('accounts/getPayment', this.payment.id))
  212. .then(() => { this.failing = false; })
  213. .catch(() => { this.failing = false; });
  214. },
  215. delivery() {
  216. this.deliverLoading = true;
  217. this.update({ id: this.payment.id, action: 'delivery', details: this.details })
  218. .then(() => this.$store.dispatch('accounts/getPayment', this.payment.id))
  219. .then(() => {
  220. this.deliverLoading = false;
  221. this.delivering = false;
  222. })
  223. .catch(() => {
  224. this.deliverLoading = false;
  225. this.delivering = false;
  226. });
  227. },
  228. update(data) {
  229. return this.$store.dispatch('accounts/updatePayment', data);
  230. },
  231. },
  232. computed: {
  233. ...mapState({
  234. payment: ({ accounts }) => accounts.payment,
  235. }),
  236. ...mapGetters({ username: 'user/username' }),
  237. pass() {
  238. const { status, to, escrow_settlement: escrow } = this.payment;
  239. if (status === 'requested' && to !== this.username && escrow) {
  240. return 'accept';
  241. }
  242. if ((status === 'requested' && to !== this.username && !escrow)
  243. || (status === 'delivered' && to !== this.username)) {
  244. return 'settle';
  245. }
  246. if (status === 'funded' && to === this.username) {
  247. return 'delivery';
  248. }
  249. return false;
  250. },
  251. fail() {
  252. const { status, to } = this.payment;
  253. if (status === 'requested' && to !== this.username) {
  254. return 'reject';
  255. }
  256. if (status === 'funded' && to === this.username) {
  257. return 'cancel';
  258. }
  259. if (status === 'delivered' && to !== this.username) {
  260. return 'dispute';
  261. }
  262. return false;
  263. },
  264. },
  265. };
  266.  
  267. // AccountDetails.js
  268. import { math } from '@/utils';
  269. import { mapState, mapGetters } from 'vuex';
  270. import {
  271. Order,
  272. Deposit,
  273. Withdrawal,
  274. Payment,
  275. } from '@/components/Modals';
  276.  
  277. export default {
  278. components: {
  279. Order,
  280. Deposit,
  281. Withdrawal,
  282. Payment,
  283. },
  284. mixins: [math],
  285. data: () => ({
  286. order: {},
  287. deposit: {},
  288. withdrawal: {},
  289. payment: {},
  290. loading: false,
  291. pagination: {
  292. sortBy: 'date',
  293. descending: true,
  294. },
  295. headers: [
  296. { align: 'left', value: 'date' },
  297. { align: 'right', value: 'amount' },
  298. { align: 'right', value: 'fee' },
  299. { align: 'right', value: 'usd' },
  300. { align: 'right', value: 'type' },
  301. { align: 'right', value: 'info' },
  302. { align: 'right', value: 'status' },
  303. ],
  304. }),
  305. watch: {
  306. pagination: {
  307. handler() {
  308. this.loading = true;
  309. this.$store.dispatch('accounts/getDetails', this.pagination)
  310. .then(() => {
  311. this.loading = false;
  312. });
  313. },
  314. deep: true,
  315. },
  316. },
  317. methods: {
  318. parsePayment(info) {
  319. if (!info) return '';
  320. if (info[0] === 'c' || !isNaN(info)) return 'Card';
  321. if (info[0] === 'p') return 'Bank';
  322. if (info.match(/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}/g)
  323. || info === 'BitShares') return 'Crypto';
  324. return info;
  325. },
  326. capitalize(value) {
  327. if (!value) return '';
  328. value = value.toString();
  329. return value.charAt(0).toUpperCase() + value.slice(1);
  330. },
  331. open(item) {
  332. this[item.type.toLowerCase()] = {
  333. open: true,
  334. id: item.id,
  335. };
  336. },
  337. },
  338. computed: {
  339. ...mapState({
  340. details: ({ accounts }) => accounts.details,
  341. total: ({ accounts }) => accounts.totalDetails,
  342. }),
  343. ...mapGetters({
  344. account: 'accounts/selected',
  345. }),
  346. },
  347. };
  348.  
  349. // EXPRESS/NODEJS API
  350. // payments.js
  351.  
  352. // Dependencies
  353. const router = require('express').Router();
  354. const { coinbase, mail, authy } = require('../../lib');
  355. const { Payment, User, Account } = require('../../models');
  356.  
  357. /**
  358. * POST api.quintric.com/app/payments
  359. * Initiate a payment to another user based on username
  360. *
  361. * Body: {
  362. * Integer token: id of token sending,
  363. * String username: username of account sending to,
  364. * String description: description of goods/services,
  365. * Integer amount: amount to send,
  366. * Integer fee: fee (calculated on component),
  367. * }
  368. *
  369. * Response: 201
  370. */
  371. router.post('', async (req, res, next) => {
  372. const body = req.body;
  373. let from;
  374. let to;
  375. let escrow;
  376.  
  377. Account.getByUserId(req.user.id, body.token)
  378. .then((account) => {
  379. from = account;
  380. return Account.getByUserId(10, body.token);
  381. })
  382. .then((account) => {
  383. escrow = account;
  384. return User.get(body.username);
  385. })
  386. .then((user) => {
  387. if (user) return Account.getByUserId(user.id, body.token);
  388. else return { id: -1 };
  389. })
  390. .then((user) => {
  391. to = user.id < 0 ? false : user;
  392. return Payment.create({
  393. ...body,
  394. from: from.id,
  395. to: user.id,
  396. })
  397. })
  398. .then(payment => payment.addStatus('sent', body.username.toLowerCase()))
  399. .then(() => from.subtractBalance(+body.amount))
  400. .then(() => escrow.addBalance(+body.fee))
  401. .then(() => !!to ? to.addBalance((+body.amount) - (+body.fee)) : null)
  402. .then(() => mail.send(`payments/${!!to ? 'invite' : 'sent'}`, body.username, {}))
  403. .then(() => res.status(201).json({ message: 'Payment has been sent' }))
  404. .catch(err => next(err));
  405. });
  406.  
  407. /**
  408. * POST api.quintric.com/app/payments/request
  409. * Request a payment from another user based on username
  410. *
  411. * Body: {
  412. * Integer token: id of token sending,
  413. * String username: username of account requesting from,
  414. * Integer amount: amount to send,
  415. * String description: description of goods/services,
  416. * Boolean escrow: true for net 30 terms,
  417. * Integer fee: fee (calculated on component),
  418. * }
  419. *
  420. * Response: 201
  421. */
  422. router.post('/request', async (req, res, next) => {
  423. const body = req.body;
  424.  
  425. const to = await Account.getByUserId(req.user.id, body.token);
  426. const from = await Account.getByUsername(body.username, body.token);
  427.  
  428. const options = {
  429. ...body,
  430. from: from.id,
  431. to: to.id,
  432. };
  433.  
  434. Payment.create(options)
  435. .then(payment => payment.addStatus('requested', body.username))
  436. .then(() => to.username())
  437. .then((user) => mail.send('paymentRequested', user, {}))
  438. .then(() => res.status(201).json({ message: 'Payment has been requested' }))
  439. .catch(err => next(err));
  440. });
  441.  
  442. /**
  443. * POST api.quintric.com/app/payments/token
  444. * Create and settle a payment request verified with Authy Soft Token
  445. *
  446. * Body: {
  447. * Integer token: id of token sending,
  448. * String username: username of account requesting from,
  449. * Integer amount: amount to send,
  450. * String description: description of goods/services,
  451. * String softToken: soft token verifying counterpary compliance,
  452. * }
  453. *
  454. * Response: 201
  455. */
  456. router.post('/token', async (req, res, next) => {
  457. const { softToken, token, username, amount, description } = req.body;
  458.  
  459. const to = await Account.getByUserId(req.user.id, token);
  460. const from = await Account.getByUsername(username, token);
  461. const escrow = await Account.getByUserId(10, token);
  462.  
  463. let fee = amount * .01;
  464. fee = fee < 5 ? fee : 5;
  465.  
  466. const options = {
  467. amount,
  468. description,
  469. fee,
  470. from: from.id,
  471. to: to.id,
  472. };
  473.  
  474. User.get(username)
  475. .then(user => user.getAuthyId())
  476. .then(authyId => authy.verifyToken(authyId, softToken))
  477. .then(() => Payment.create(options))
  478. .then(payment => payment.addStatus('settled', 'Token Verification'))
  479. .then(() => to.addBalance(amount - fee))
  480. .then(() => escrow.addBalance(fee))
  481. .then(() => from.subtractBalance(amount))
  482. .then(() => to.username())
  483. .then((user) => mail.send('paymentRequested', user, {}))
  484. .then(() => res.status(201).json({ message: 'Payment successfully settled.' }))
  485. .catch(err => next(err));
  486. });
  487.  
  488. /**
  489. * GET api.quintric.com/app/address
  490. * Get list of addresses attached to current user for account funding
  491. *
  492. * Query: {
  493. * Integer token: id of token sending,
  494. * }
  495. *
  496. * Response: 200
  497. */
  498. router.get('/address', (req, res, next) => {
  499.  
  500. const chargeData = {
  501. 'name': 'Quintric',
  502. 'metadata': {
  503. 'token': req.query.token,
  504. 'user': req.user.getId(),
  505. },
  506. 'description': 'Account Funding',
  507. 'pricing_type': 'no_price'
  508. };
  509.  
  510. coinbase.Charge.create(chargeData, (err, response) => {
  511. if (err) return next(err)
  512. return res.send(response.addresses);
  513. });
  514. });
  515.  
  516. module.exports = router;
Add Comment
Please, Sign In to add comment