Skip to content

Commit

Permalink
이슈별 트랜잭션 관리 JAVACAFE-STUDY#183
Browse files Browse the repository at this point in the history
  • Loading branch information
clghks committed Oct 14, 2018
1 parent a0d595f commit 479004e
Show file tree
Hide file tree
Showing 12 changed files with 299 additions and 11 deletions.
9 changes: 8 additions & 1 deletion backend/controllers/issue.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ function addParticipant(req, res, next) {
.catch(e => next(e));
}

function addTransaction(req, res, next) {
const issue = new Issue(req.issue);
Issue.update({ id: issue.id}, { $addToSet: { transactions: req.params.transactionId } })
.then(savedIssue => res.json(savedIssue))
.catch(e => next(e));
}

/**
* Remove participant
*/
Expand All @@ -151,4 +158,4 @@ function removeParticipant(req, res, next) {
.catch(e => next(e));
}

module.exports = { list, create, load, get, update, remove, addParticipant, removeParticipant };
module.exports = { list, create, load, get, update, remove, addParticipant, removeParticipant, addTransaction };
43 changes: 43 additions & 0 deletions backend/controllers/transaction.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
var httpStatus = require('http-status');
var APIError = require('../helpers/APIError');
var Transaction = require('../models/transaction.model');

/**
* Get Transaction list.
* @property {number} req.query.skip - Number of tansaction to be skipped.
* @property {number} req.query.limit - Limit number of tansaction to be returned.
* @returns {TokensRequest[]}
*/
function list(req, res, next) {
const { limit = 50, skip = 0 } = req.query;
Transaction.list({ limit, skip })
.then(transaction => res.json(transaction))
.catch(e => next(e));
}

/**
* Create new Transaction
* @property {string} req.body.txHash - The txHash of Transaction.
* @property {string} req.body.toAddress - The toAddress of Transaction.
* @property {string} req.body.fromAddress - The fromAddress of Transaction.
* @property {string} req.body.tokenValue - The tokenValue of Transaction.
* @property {string} req.body.txType - The txType of Transaction.
* @returns {User}
*/
function create(req, res, next) {
const transaction = new Transaction({
txHash: req.body.txHash,
toAddress: req.body.toAddress,
fromAddress: req.body.fromAddress,
tokenValue: req.body.tokenValue,
txType: req.body.txType
});

transaction.save()
.then(savedTransaction => res.json(savedTransaction))
.catch((e) => {
next(new APIError(e.message, httpStatus.BAD_REQUEST));
});
}

module.exports = { list, create };
5 changes: 5 additions & 0 deletions backend/models/issue.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const IssueSchema = new mongoose.Schema({
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}],
transactions: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Transaction'
}],
isClosed: {
type: Boolean,
required: true
Expand Down Expand Up @@ -98,6 +102,7 @@ IssueSchema.statics = {
return this.findOne({ id: parseInt(id) })
.populate('participants')
.populate('completedParticipants')
.populate('transactions')
.populate('createdBy')
.exec()
.then((issue) => {
Expand Down
109 changes: 109 additions & 0 deletions backend/models/transaction.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
var Promise = require('bluebird');
var mongoose = require('mongoose');
var httpStatus = require('http-status');
var APIError = require('../helpers/APIError');
var config = require('../config/config');
var ObjectID = require('mongodb').ObjectID

mongoose.connect('mongodb://' + config.mongo.host + ':' + config.mongo.port);

/**
* User Schema
*/
const TransactionsSchema = new mongoose.Schema({
txHash: {
type: String,
required: true,
unique : true
},
toAddress: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
fromAddress: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
tokenValue: {
type: Number,
required: true
},
txType: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
registeredAt: {
type: Date
}
}, {
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
});

/**
* Add your
* - pre-save hooks
* - validations
* - virtuals
*/

/**
* Methods
*/
TransactionsSchema.method({
});

/**
* Statics
*/
TransactionsSchema.statics = {
/**
* Get transactions
* @param {ObjectId} id - The objectId of transaction.
* @returns {Promise<User, APIError>}
*/
get(id) {
return this.findOne({ id: parseInt(id) })
.populate('toAddress')
.populate('fromAddress')
.exec()
.then((transaction) => {
if (transaction) {
return transaction;
}
const err = new APIError('No such Transaction exists!', httpStatus.NOT_FOUND);
return Promise.reject(err);
});
},

/**
* List transactions in descending order of 'createdAt' timestamp.
* @param {number} skip - Number of transactions to be skipped.
* @param {number} limit - Limit number of transactions to be returned.
* @returns {Promise<User[]>}
*/
list({ skip = 0, limit = 50, q = {} } = {}) {
return this.find(q)
.populate('toAddress')
.populate('fromAddress')
.sort({ createdAt: -1 })
.skip(+skip)
.limit(+limit)
.exec();
}
};

/**
* @typedef Transactions
*/
module.exports = mongoose.model('Transaction', TransactionsSchema);
12 changes: 8 additions & 4 deletions backend/routes/index.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ var authRoutes = require('./auth.route');
var userRoutes = require('./user.route');
var issueRoutes = require('./issue.route');
var mailRoutes = require('./mail.route');
var bankRoutes = require('./bank.route')
var tokensRequestRoutes = require('./tokensRequest.route')
var contractRoutes = require('./contract.route')
var bankRoutes = require('./bank.route');
var transactions = require('./transaction.route');
var tokensRequestRoutes = require('./tokensRequest.route');
var contractRoutes = require('./contract.route');
var imageRoutes = require('./image.route');

const router = express.Router(); // eslint-disable-line new-cap
const auth = expressJwt({secret: config.jwtSecret, requestProperty: 'decoded'})
const auth = expressJwt({secret: config.jwtSecret, requestProperty: 'decoded'});

/** GET /health-check - Check service health */
router.get('/health-check', (req, res) =>
Expand All @@ -38,6 +39,9 @@ router.use('/banks', auth, bankRoutes);
// mount contract routes at /contracts
router.use('/contracts', auth, contractRoutes);

// mount transaction routes at /transactions
router.use('/transactions', auth, transactions);

// mount image routes at /image
router.use('/images', imageRoutes);

Expand Down
5 changes: 5 additions & 0 deletions backend/routes/issue.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ router.route('/:issueId/participants/:userId')
// DELETE /api/issues/:issueId/participants/:userId - Remove participant in issue
.delete(issueCtrl.removeParticipant);

router.route('/:issueId/transaction/:transactionId')
// PUT /api/issues/:issueId/transaction/:transactionId - Add participant in issue
.put(issueCtrl.addTransaction);


// Load issue when API with issueId route parameter is hit
router.param('issueId', issueCtrl.load);

Expand Down
12 changes: 12 additions & 0 deletions backend/routes/transaction.route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var express = require('express');
var transactionCtrl = require('../controllers/transaction.controller');

const router = express.Router();

router.route('/')
// GET /api/transactions - Get list of transaction
.get(transactionCtrl.list)
// POST /api/transactions - Create new transaction
.post(transactionCtrl.create);

module.exports = router;
5 changes: 5 additions & 0 deletions frontend/src/_nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export default {
url: '/receipt',
icon: 'icon-speedometer'
},
{
name: '거래내역(DB)',
url: '/transaction',
icon: 'icon-speedometer'
},
{
name: '관리자메뉴',
url: '/admin',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import Receipt from '@/views/Receipt'
import MyTokens from '@/views/MyTokens'
import RegisterRequests from '@/views/RegisterRequests'
import UsersRole from '@/views/UsersRole'
import Transaction from '@/views/Transaction'

import crypto from 'crypto'

Expand Down Expand Up @@ -105,6 +106,12 @@ export default new Router({
component: Purchase,
beforeEnter: requireAuth
},
{
path: 'transaction',
name: '거래내역',
component: Transaction,
beforeEnter: requireAuth
},
{
path: 'admin',
redirect: '/admin/tokens-requests',
Expand Down
43 changes: 37 additions & 6 deletions frontend/src/views/Issue.vue
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@
</b-card>
</b-col>
</b-row>

<b-row>
<b-col sm="12">
<c-table ref="table" v-if="transactions.length > 0" striped :rows="transactions" :columns="transactionFields" caption="<i class='fa fa-align-justify'></i> 토큰 거래 내역"></c-table>
</b-col><!--/.col-->
</b-row><!--/.row-->
</b-card>
<pw-modal></pw-modal>
<reward-modal></reward-modal>
Expand All @@ -123,12 +129,14 @@
<script>
import pwModal from './notifications/PasswordModal.vue'
import rewardModal from './notifications/RewardModal.vue'
import cTable from './base/Table.vue'
export default {
name: 'issue',
components: {
pwModal,
rewardModal
rewardModal,
cTable
},
async created () {
await this.fetchUser()
Expand All @@ -149,7 +157,16 @@ export default {
participants: [],
completedParticipants: []
},
user: {}
user: {},
transactions: [],
transactionFields: [
{key: 'transactionFromName', label: '발신자', sortable: true},
{key: 'transactionToName', label: '수신자', sortable: true},
{key: 'tokenValue', label: '전송토큰', sortable: true},
{key: 'txType', label: '타입', sortable: true},
{key: 'createdAt', label: 'createdAt', sortable: true},
{key: 'txHash', label: '상세이력', sortable: true}
]
}
},
methods: {
Expand All @@ -158,6 +175,7 @@ export default {
this.$http.get('/api/issues/' + this.$route.params.id)
.then((response) => {
this.form = response.data
this.transactions = response.data.transactions
})
},
fetchUser () {
Expand All @@ -184,8 +202,8 @@ export default {
askPermissionAndOptIn () {
var participants = this.form.participants.length + this.form.completedParticipants.length
if (participants >= this.form.maxNumberOfParticipants) {
alert("참여 가능 인원 수가 이미 꽉 찼습니다.")
return
alert('참여 가능 인원 수가 이미 꽉 찼습니다.')
return
}
var tokenOwnerName = this.user.name
var spenderName = this.form.createdBy.name
Expand Down Expand Up @@ -252,8 +270,8 @@ export default {
optIn () {
var participants = this.form.participants.length + this.form.completedParticipants.length
if (participants >= this.form.maxNumberOfParticipants) {
alert("참여 가능 인원 수가 이미 꽉 찼습니다.")
return
alert('참여 가능 인원 수가 이미 꽉 찼습니다.')
return
}
this.$http.put('/api/issues/' + this.$route.params.id + '/participants/me')
.then((response) => {
Expand Down Expand Up @@ -291,10 +309,23 @@ export default {
tokens: tokens,
password: password
}
var transactionBody = {
toAddress: participant._id,
fromAddress: this.form.createdBy._id,
tokenValue: tokens,
txType: this.form.issueType
}
this.$http.post('/api/contracts/mine/approval', body)
.then((response) => {
transactionBody.txHash = response.data.txHash
return this.$http.post('/api/transactions', transactionBody)
// this.optOut()
})
.then((response) => {
return this.$http.put('/api/issues/' + this.$route.params.id + '/transaction/' + response.data._id)
}).then((response) => {
alert('토큰 전송완료')
})
.catch((error) => {
alert(error.response.data.message)
})
Expand Down
Loading

0 comments on commit 479004e

Please sign in to comment.