Skip to content

Commit fa86108

Browse files
committed
add country for JB discount, add order admin for courses
1 parent ced2db8 commit fa86108

16 files changed

Lines changed: 278 additions & 37 deletions

File tree

Install.md

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,17 @@ sudo port install nginx +debug+gzip_static+realip+geoip
5454
sudo port load nginx
5555
```
5656

57-
## 6. Конфигурация Nginx
57+
## 6. Конфигурация Nginx с нуля
5858

59-
Если в системе ранее не стоял nginx.
59+
Если в системе ранее не стоял nginx, то поставьте его.
60+
61+
Логи nginx пишет в директорию `/var/log/nginx`.
62+
63+
Если её нет, то нужно создать и поставить пермишны/владельца. Например, если компьютер – ваш личный, то запустить от рута:
64+
```
65+
mkdir /var/log/nginx
66+
chmod 777 /var/log/nginx
67+
```
6068

6169
Cтавим настройки для сайта запуском:
6270
```
@@ -66,24 +74,33 @@ gulp config:nginx --prefix /opt/local/etc/nginx --root /js/javascript-nodejs --e
6674
Здесь `--prefix` -- место для конфигов nginx, обычно `/etc/nginx`, в случае MacPorts это `/opt/local/etc/nginx`.
6775
В параметр `--root` запишите место установки сайта.
6876

69-
Опция `--clear` полностью удалит старые конфиги nginx.
77+
В `--root` находится путь к движку: если вы использовали другой путь для сайта, вместо `/js/javascript-nodejs`, то измените его.
7078

71-
Если уже есть nginx, то можно без `--clear`.
79+
Опция `--clear` полностью удалит старые конфиги nginx.
7280

81+
Также рекомендуется в `/etc/hosts` добавить строку:
7382
```
74-
gulp config:nginx --prefix /opt/local/etc/nginx --root /js/javascript-nodejs --env development
83+
127.0.0.1 javascript.in
7584
```
7685

77-
Такая команда скопирует файлы из директории nginx в указанную директорию `--prefix`. При копировании используется небольшая шаблонизация конфигов, т.е. это не просто `cp`.
86+
Такое имя хоста стоит в конфигурации Nginx.
87+
88+
## 6.1. Если Nginx у вас уже стоит
7889

79-
Основные конфиги будут при этом перезаписаны, но в `sites-enabled` останутся и будут подключены и другие сайты.
90+
Если уже есть nginx, то сделайте резервную копию всех его конфигов.
8091

81-
Также рекомендуется в `/etc/hosts` добавить строку:
92+
После этого выполните предыдущую секцию без `--clear` в команде:
93+
8294
```
83-
127.0.0.1 javascript.in
95+
gulp config:nginx --prefix /opt/local/etc/nginx --root /js/javascript-nodejs --env development
8496
```
8597

86-
Такое имя хоста стоит в конфигурации Nginx.
98+
Такая команда скопирует файлы из директории `/js/javascript-nodejs/nginx` в указанную директорию `--prefix`, но без перезаписывания.
99+
При копировании используется небольшая шаблонизация конфигов, т.е. это не просто `cp`, но структура файлов остаётся такой же.
100+
101+
Основные конфиги будут перезаписаны, но в `sites-enabled` останутся и будут подключены и другие сайты.
102+
103+
Перезапустите Nginx. Проверьте, что ваши предыдущие проекты работают.
87104

88105
## 7. `npm install`
89106

@@ -108,12 +125,16 @@ cd /js
108125
git clone -b ru --single-branch https://github.com/iliakan/javascript-tutorial
109126
```
110127

111-
После клонирования импортируйте учебник командой:
128+
После клонирования импортируйте учебник в базу командой:
112129
```
113-
gulp tutorial:import --root /js/javascript-tutorial
130+
PLUNK_REMOTE_OFF=1 gulp tutorial:import --root /js/javascript-tutorial
114131
```
115132

116-
Здесь `/js/javascript=tutorial` -- директория с репозитарием учебника.
133+
Здесь `/js/javascript-tutorial` -- директория с репозитарием учебника.
134+
135+
`PLUNK_REMOTE_OFF=1` отключает автоматическую загрузку примеров из учебников на сервис plnkr.co.
136+
Она требует настройки сессии на plnkr.co и нужна при публикации учебника.
137+
Для запуска проекта она не нужна, особенно если вас интересуют другие модули.
117138

118139
## 9. Запуск сайта
119140

handlers/courses/controller/invite.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ function* askParticipantDetails(invite) {
153153
participantData.user = this.user._id;
154154
participantData.group = invite.group._id;
155155

156+
participantData.invite = invite;
157+
156158
if (participantData.photoId) {
157159
var photo = yield ImgurImage.findOne({imgurId: this.request.body.photoId}).exec();
158160
if (photo) { // no photo if stale form (?) or just bad post
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
var _ = require('lodash');
2+
var Order = require('payments').Order;
3+
var Transaction = require('payments').Transaction;
4+
var User = require('users').User;
5+
var CourseParticipant = require('../models/courseParticipant');
6+
7+
exports.get = function*() {
8+
9+
yield* this.loadOrder();
10+
11+
if (!this.order) {
12+
this.throw(404, 'Нет такого заказа.');
13+
}
14+
15+
var transactions = yield Transaction.find({order: this.order._id}).sort({modified: -1});
16+
this.locals.order = this.order;
17+
this.locals.transactions = transactions;
18+
19+
this.body = this.render('admin/order');
20+
};
21+
22+
23+
exports.post = function*() {
24+
25+
yield* this.loadOrder();
26+
27+
if (!this.order) {
28+
this.throw(404, 'Нет такого заказа.');
29+
}
30+
31+
32+
this.order.amount = this.request.body.amount;
33+
34+
35+
if (this.order.status == Order.STATUS_CANCEL) {
36+
37+
if (this.request.body.action == 'pending') {
38+
this.order.status = Order.STATUS_PENDING;
39+
} else if (this.request.body.action == 'paid') {
40+
yield* this.order.onPaid();
41+
42+
this.order.status = Order.STATUS_SUCCESS;
43+
}
44+
} else if (this.order.status == Order.STATUS_PENDING) {
45+
if (this.request.body.action == 'paid') {
46+
yield* this.order.onPaid();
47+
48+
this.order.status = Order.STATUS_SUCCESS;
49+
}
50+
} else if (this.order.status == Order.STATUS_SUCCESS) {
51+
if (this.request.body.action == 'cancel') {
52+
this.order.status = Order.STATUS_CANCEL;
53+
54+
var userIdsByEmails = yield User.find({
55+
email: {
56+
$in: this.order.data.emails
57+
}
58+
}, {id: 1});
59+
60+
userIdsByEmails = userIdsByEmails.map(user => user._id);
61+
62+
var participants = yield CourseParticipant.find({
63+
group: this.order.data.group,
64+
user: {
65+
$in: userIdsByEmails
66+
},
67+
isActive: true
68+
});
69+
70+
this.log.debug("cancel participants", participants);
71+
72+
for (var i = 0; i < participants.length; i++) {
73+
var participant = participants[i];
74+
yield participant.persist({
75+
isActive: false
76+
});
77+
}
78+
79+
}
80+
}
81+
82+
yield this.order.persist();
83+
84+
this.redirect(this.originalUrl);
85+
86+
};
87+

handlers/courses/lib/cancelIfPendingTooLong.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ module.exports = function*(order) {
2727

2828
if (orderSuccessSameGroupAndUser) {
2929
// 2 days if has success order to same group
30-
if (order.created > Date.now() - 2 * 86400 * 1e3) {
31-
//console.log(order.created, Date.now() - 2 * 24 * 86400 * 1e3, +order.created);
32-
gutil.log(`...created ${order.created} less than 2 days, return`);
30+
if (order.modified > Date.now() - 2 * 86400 * 1e3) {
31+
//console.log(order.modified, Date.now() - 2 * 24 * 86400 * 1e3, +order.modified);
32+
gutil.log(`...modified ${order.modified} less than 2 days, return`);
3333
return;
3434
}
3535
} else {
3636
// 7 days wait otherwise
37-
if (order.created > Date.now() - 7 * 86400 * 1e3) {
38-
gutil.log(`...created ${order.created} less than 7 days, return`);
37+
if (order.modified > Date.now() - 7 * 86400 * 1e3) {
38+
gutil.log(`...modified ${order.modified} less than 7 days, return`);
3939
return;
4040
}
4141
}

handlers/courses/lib/patch.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
"use strict";
22

3-
const CourseGroup = require('../models/courseGroup');
43
const CourseParticipant = require('../models/courseParticipant');
5-
const CourseInvite = require('../models/courseInvite');
64
const _ = require('lodash');
75
const sendOrderInvites = require('./sendOrderInvites');
86
const Order = require('payments').Order;
9-
const User = require('users').User;
107

118
// called by payments/common/order
129
module.exports = function*() {
1310

1411
//var group = yield CourseGroup.findById(this.order.data.group).exec();
1512
var participants = yield CourseParticipant.find({
1613
group: this.order.data.group
17-
}).populate('user').exec();
14+
}).populate('user');
1815

1916
var participantsByEmail = _.indexBy(participants, function(participant) {
2017
return participant.user.email;
@@ -63,6 +60,21 @@ module.exports = function*() {
6360
}
6461

6562
this.order.markModified('data');
63+
64+
if (this.isAdmin) {
65+
if ("amount" in this.request.body) {
66+
this.order.amount = this.request.body.amount;
67+
}
68+
69+
if ("currency" in this.request.body) {
70+
this.order.currency = this.request.body.currency;
71+
}
72+
73+
if ("status" in this.request.body) {
74+
this.order.status = this.request.body.status;
75+
}
76+
}
77+
6678
yield this.order.persist();
6779

6880

handlers/courses/lib/registerParticipants.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,14 @@ function* grantXmppChatMemberships(group, participants, teacher) {
8787
// grant all in parallel
8888
yield jobs;
8989

90-
// TODO: test me teacher access!!
91-
// profileName or fullName here?
92-
9390
log.debug("adding user");
9491

9592
yield client.grantMember(roomJid, teacher.profileName + '@' + config.xmpp.server, teacher.displayName, 'owner');
96-
// yield client.grantModerator(roomJid, teacher.displayName);
9793

9894
client.disconnect();
9995
}
10096

101-
// when user updates his details, regrant his groups, just in case he changed his name
97+
// when user updates his details, regrant his groups IF changed profileName
10298
User.schema.pre('save', function(next) {
10399
var user = this;
104100
co(function*() {

handlers/courses/models/courseInvite.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var schema = new Schema({
1111
order: {
1212
type: Schema.Types.ObjectId,
1313
ref: 'Order'
14-
// not required, invite may exist without an order ("free second time" for people who had problems)
14+
// not required, invite may exist without an order ("free second time" for people who had problems?)
1515
},
1616

1717
// when order is null,

handlers/courses/models/courseParticipant.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ var schema = new Schema({
2626
default: true
2727
},
2828

29+
// for history how this participant was created
30+
invite: {
31+
type: Schema.Types.ObjectId,
32+
ref: 'CourseInvite'
33+
// should be required, but added after participants w/o it existed already
34+
},
35+
36+
notes: {
37+
type: String
38+
},
39+
2940
firstName: {
3041
type: String,
3142
validate: [

handlers/courses/router.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ router.get('/:course', require('./controller/course').get);
2323
router.get('/groups/:groupBySlug/signup', require('./controller/signup').get);
2424
router.get('/orders/:orderNumber(\\d+)', require('./controller/signup').get);
2525

26+
router.get('/admin/orders/:orderNumber(\\d+)', mustBeAdmin, require('./controller/order').get);
27+
router.post('/admin/orders/:orderNumber(\\d+)', mustBeAdmin, require('./controller/order').post);
28+
2629
router.get('/groups/:groupBySlug/info', mustBeParticipantOrTeacher, require('./controller/groupInfo').get);
2730
router.get('/groups/:groupBySlug/materials', mustBeParticipantOrTeacher, require('./controller/groupMaterials').get);
2831
router.get('/groups/:groupBySlug/participants-info', mustBeTeacherOrAdmin, require('./controller/participantsInfo').get);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
extends /layouts/main
2+
3+
block append variables
4+
5+
- var layout_header_class = "main__header_center"
6+
- var title = 'Заказ ' + order.number;
7+
- var sitetoolbar = true
8+
- var siteToolbarCurrentSection = "courses";
9+
10+
block content
11+
12+
p= order.title
13+
14+
form(method="POST" action="")
15+
input(type="hidden", name="_csrf", value=csrf())
16+
div
17+
label
18+
| Стоимость:
19+
= ' '
20+
input(name="amount" required value=order.amount)
21+
= ' ' + order.currency
22+
div
23+
| Статус: <b>#{order.status}</b>
24+
25+
26+
h2 Транзакции
27+
table
28+
tr
29+
th modified
30+
th created
31+
th paymentMethod
32+
th amount
33+
th currency
34+
th status
35+
th statusMessage
36+
each transaction in transactions
37+
tr
38+
td= moment(transaction.modified).format('DD.MM.YYYY HH:mm:ss')
39+
td= moment(transaction.created).format('DD.MM.YYYY HH:mm:ss')
40+
td= transaction.paymentMethod
41+
td= transaction.amount
42+
td= transaction.currency
43+
td= transaction.status
44+
td= transaction.statusMessage
45+
if transaction.paymentMethod == 'invoice' && transaction.paymentDetails.agreementRequired
46+
tr
47+
td(colspan=7) Скачать <a href="/payments/invoice/#{transaction.number}/invoice.docx">счёт</a> и <a href="/payments/invoice/#{transaction.number}/agreement.docx">договор с актом</a>.
48+
49+
p Действия
50+
ul
51+
li
52+
+b('button').button._action(name="action" value="save" type="submit")
53+
+e('span').text Сохранить
54+
55+
if order.status == 'cancel'
56+
li
57+
+b('button').button._action(name="action" value="pending" type="submit")
58+
+e('span').text Вернуть в Pending
59+
li
60+
+b('button').button._action(name="action" value="paid" type="submit")
61+
+e('span').text Оплачен
62+
63+
if order.status == 'pending'
64+
li
65+
+b('button').button._action(name="action" value="paid" type="submit")
66+
+e('span').text Оплачен
67+
68+
if order.status == 'success'
69+
li
70+
+b('button').button._action(name="action" value="cancel" type="submit")
71+
+e('span').text Отменить и отчислить участников
72+
73+

0 commit comments

Comments
 (0)