Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FRONTEND_HOST=http://localhost:8082
API_HOST="http://localhost:3000"
PAYPAL_HOST="https://api.sandbox.paypal.com"
SLACK_WEBHOOK_URL=

FACEBOOK_ID=123
FACEBOOK_SECRET=123
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,4 @@ Thumbs.db
# Configuration of database and password/tokens/idSercure
.env
docker-compose.override.yml
.claude/
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ interface IssueActionsProps {
fetchTask: (taskId: number) => void
syncTask: (taskId: number) => void
taskSolutionCompleted: boolean
validateCoupon?: (code: string, originalOrderPrice: number) => void
couponStoreState?: any
}

const IssueActionsByRole = ({
Expand Down Expand Up @@ -61,7 +63,9 @@ const IssueActionsByRole = ({
listWallets,
wallets,
fetchTask,
syncTask
syncTask,
validateCoupon,
couponStoreState
}: IssueActionsProps) => {
const { data } = issue

Expand Down Expand Up @@ -98,6 +102,8 @@ const IssueActionsByRole = ({
fetchTask={fetchTask}
syncTask={syncTask}
price={data?.price || 0}
validateCoupon={validateCoupon}
couponStoreState={couponStoreState}
/>
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import Checkboxes from '../../checkboxes/checkboxes'
import { FormattedMessage } from 'react-intl'

const UserRoleField = ({ roles, onChange }) => {
const { data, completed } = roles
const { data = [], completed = false } = roles || {}

const checkBoxes = useMemo(
() =>
data.map((role) => ({
label: role.label,
name: role.name,
value: role.id
})),
Array.isArray(data)
? data.map((role) => ({
label: role.label,
name: role.name,
value: role.id
}))
: [],
[data]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ function IssuePaymentDrawer({
listWallets,
wallets,
fetchTask,
syncTask
syncTask,
validateCoupon,
couponStoreState
}: any) {
const intl = useIntl()

Expand Down Expand Up @@ -152,6 +154,8 @@ function IssuePaymentDrawer({
task={task?.data}
plan={plan}
onClose={onClose}
validateCoupon={validateCoupon}
couponStoreState={couponStoreState}
/>
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ const IssueSidebar = ({
wallets,
fetchTask,
syncTask,
validateCoupon,
couponStoreState,
fetchCustomer
}) => {
const intl = useIntl()
Expand Down Expand Up @@ -294,6 +296,8 @@ const IssueSidebar = ({
wallets={wallets}
fetchTask={fetchTask}
syncTask={syncTask}
validateCoupon={validateCoupon}
couponStoreState={couponStoreState}
/>

<IssueInviteCard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ const CheckoutForm = (props) => {
}

if (!stripe || !elements) {
props.addNotification('payment.message.error', 'Stripe not initialized')
if (props.addNotification && typeof props.addNotification === 'function') {
props.addNotification('payment.message.error', 'Stripe not initialized')
} else {
console.error('Stripe not initialized and addNotification is not available')
}
setCheckoutFormState((prev) => ({ ...prev, paymentRequested: false }))
return
}
Expand Down Expand Up @@ -95,7 +99,11 @@ const CheckoutForm = (props) => {
}
} catch (e) {
console.log('Error creating token or processing payment:', e)
props.addNotification('payment.message.error', e.message || 'Error processing payment')
if (props.addNotification && typeof props.addNotification === 'function') {
props.addNotification('payment.message.error', e.message || 'Error processing payment')
} else {
console.error('Payment error:', e.message || 'Error processing payment')
}
setCheckoutFormState((prev) => ({ ...prev, paymentRequested: false }))
}
}
Expand Down Expand Up @@ -148,7 +156,11 @@ const CheckoutForm = (props) => {
}

const applyCoupon = () => {
props.validateCoupon(couponState.coupon, price)
if (props.validateCoupon && typeof props.validateCoupon === 'function') {
props.validateCoupon(couponState.coupon, price)
} else {
console.error('validateCoupon is not available')
}
}

const logged = checkoutFormState.authenticated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const IssuePage = ({
listWallets,
wallets,
fetchTask,
syncTask
syncTask,
validateCoupon,
couponStoreState
}) => {
return (
<Grid container style={{ marginBottom: 4 }} alignItems="stretch">
Expand Down Expand Up @@ -74,6 +76,8 @@ const IssuePage = ({
fetchTask={fetchTask}
syncTask={syncTask}
fetchCustomer={fetchCustomer}
validateCoupon={validateCoupon}
couponStoreState={couponStoreState}
/>
</Grid>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ const IssuePrivatePage = ({
listWallets,
wallets,
fetchTask,
syncTask
syncTask,
validateCoupon,
couponStoreState
}) => {
return (
<IssuePage
Expand Down Expand Up @@ -63,6 +65,8 @@ const IssuePrivatePage = ({
wallets={wallets}
fetchTask={fetchTask}
syncTask={syncTask}
validateCoupon={validateCoupon}
couponStoreState={couponStoreState}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ const IssuePublicPage = ({
listWallets,
wallets,
fetchTask,
syncTask
syncTask,
validateCoupon,
couponStoreState
}) => {
return (
<IssuePage
Expand Down Expand Up @@ -63,6 +65,8 @@ const IssuePublicPage = ({
wallets={wallets}
fetchTask={fetchTask}
syncTask={syncTask}
validateCoupon={validateCoupon}
couponStoreState={couponStoreState}
/>
)
}
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/containers/task-private.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
detailOrder,
listOrders
} from '../actions/orderActions'
import { validateCoupon } from '../actions/couponActions'
import { fetchWallet, listWallets } from '../actions/walletActions'
import {
getTaskSolution,
Expand Down Expand Up @@ -62,7 +63,8 @@ const mapStateToProps = (state, ownProps) => {
order: state.order,
customer: state.customer,
wallets: state.wallets,
wallet: state.wallet
wallet: state.wallet,
couponStoreState: { ...state.couponReducer }
}
}

Expand Down Expand Up @@ -115,7 +117,8 @@ const mapDispatchToProps = (dispatch, ownProps) => {
fetchPullRequestData: (owner, repositoryName, pullRequestId, taskId) =>
dispatch(fetchPullRequestData(owner, repositoryName, pullRequestId, taskId)),
cleanPullRequestDataState: () => dispatch(cleanPullRequestDataState()),
fetchAccount: () => dispatch(fetchAccount())
fetchAccount: () => dispatch(fetchAccount()),
validateCoupon: (code, originalOrderPrice) => dispatch(validateCoupon(code, originalOrderPrice))
// For account menu and bottom bar props
// signOut and getInfo provided by profile container
}
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/containers/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
detailOrder,
listOrders
} from '../actions/orderActions'
import { validateCoupon } from '../actions/couponActions'
import { fetchWallet, listWallets } from '../actions/walletActions'
import {
getTaskSolution,
Expand Down Expand Up @@ -69,7 +70,8 @@ const mapStateToProps = (state, ownProps) => {
order: state.order,
customer: state.customer,
wallets: state.wallets,
wallet: state.wallet
wallet: state.wallet,
couponStoreState: { ...state.couponReducer }
}
}

Expand Down Expand Up @@ -125,6 +127,8 @@ const mapDispatchToProps = (dispatch, ownProps) => {
dispatch(fetchPullRequestData(owner, repositoryName, pullRequestId, taskId)),
cleanPullRequestDataState: () => dispatch(cleanPullRequestDataState()),
fetchAccount: () => dispatch(fetchAccount()),
validateCoupon: (code, originalOrderPrice) =>
dispatch(validateCoupon(code, originalOrderPrice)),
// For account menu and bottom bar props
signOut: () => dispatch(logOut()),
getInfo: () => dispatch(getInfoAction())
Expand Down
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@
"migrate:test:dev": "cross-env NODE_ENV=test tsx src/migrate.ts up",
"create:db:dev": "sequelize db:create --config src/config/config.json --env development",
"create:db:test:dev": "sequelize db:create --config src/config/config.json --env test",
"seed": "TYPE=seed node dist/migrate.js up",
"seed:dev": "TYPE=seed tsx src/migrate.ts up",
"seed:test": "TYPE=seed NODE_ENV=test node dist/migrate.js up",
"seed:test:dev": "TYPE=seed NODE_ENV=test tsx src/migrate.ts up",
"seed": "cross-env TYPE=seed node dist/migrate.js up",
"seed:dev": "cross-env TYPE=seed tsx src/migrate.ts up",
"seed:test": "cross-env TYPE=seed NODE_ENV=test node dist/migrate.js up",
"seed:test:dev": "cross-env TYPE=seed NODE_ENV=test tsx src/migrate.ts up",
"seed:windows:dev": "cross-env TYPE=seed tsx src/migrate.ts up",
"seed:test:windows:dev": "cross-env TYPE=seed NODE_ENV=test tsx src/migrate.ts up",
"migrate:test:rollback": "NODE_ENV=test node migrate.js prev",
"migrate:test:rollback:dev": "NODE_ENV=test tsx src/migrate.ts prev",
"migrate:test:rollback": "cross-env NODE_ENV=test node migrate.js prev",
"migrate:test:rollback:dev": "cross-env NODE_ENV=test tsx src/migrate.ts prev",
"rollback": "node dist/migrate.js prev",
"rollback:dev": "tsx src/migrate.ts down",
"rollback:test": "NODE_ENV=test node dist/migrate.js prev",
"rollback:test:dev": "NODE_ENV=test tsx src/migrate.ts prev",
"rollback:test": "cross-env NODE_ENV=test node dist/migrate.js prev",
"rollback:test:dev": "cross-env NODE_ENV=test tsx src/migrate.ts prev",
"reset": "node dist/migrate.js reset-hard",
"reset:dev": "tsx src/migrate.ts reset-hard",
"reset:test": "NODE_ENV=test node dist/migrate.js reset-hard",
"reset:test:dev": "NODE_ENV=test tsx src/migrate.ts reset-hard",
"report": "NODE_ENV=production node dist/scripts/reports/reports.js",
"reset:test": "cross-env NODE_ENV=test node dist/migrate.js reset-hard",
"reset:test:dev": "cross-env NODE_ENV=test tsx src/migrate.ts reset-hard",
"report": "cross-env NODE_ENV=production node dist/scripts/reports/reports.js",
"report:dev": "tsx src/scripts/reports/reports.js",
"build": "tsc -p tsconfig.json",
"start:dev": "nodemon --watch src --ext ts,js --exec \"tsx src/index.ts\"",
Expand Down
7 changes: 4 additions & 3 deletions src/config/secrets.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ if (process.env.NODE_ENV !== 'production') {

const databaseDev = {
username: 'postgres',
password: 'postgres',
password: process.env.DB_PASSWORD || process.env.POSTGRES_PASSWORD || 'postgres',
database: 'gitpay_dev',
host: '127.0.0.1',
port: 5432,
Expand All @@ -14,7 +14,7 @@ const databaseDev = {

const databaseTest = {
username: 'postgres',
password: 'postgres',
password: process.env.DB_PASSWORD || process.env.POSTGRES_PASSWORD || 'postgres',
database: 'gitpay_test',
host: '127.0.0.1',
port: 5432,
Expand Down Expand Up @@ -66,7 +66,8 @@ const bitbucket = {

const slack = {
token: process.env.SLACK_TOKEN,
channelId: process.env.SLACK_CHANNEL_ID
channelId: process.env.SLACK_CHANNEL_ID,
webhookUrl: process.env.SLACK_WEBHOOK_URL
}

const mailchimp = {
Expand Down
13 changes: 9 additions & 4 deletions src/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { Umzug, SequelizeStorage } from 'umzug'
import { Sequelize } from 'sequelize'
import secrets from './config/secrets'

// Get the src directory - works with both tsx and compiled code
// @ts-ignore - __dirname is available at runtime
const srcDir = typeof __dirname !== 'undefined' ? __dirname : path.resolve(process.cwd(), 'src')

const env = process.env.NODE_ENV || 'development'

const database_env = {
Expand Down Expand Up @@ -51,9 +55,10 @@ sequelize.query('SELECT current_database();').then(([res]: any) => {

const isSeed = process.env.TYPE === 'seed'

const baseDir = isSeed
? path.join(__dirname, './db/seeders')
: path.join(__dirname, './db/migrations')
const baseDir = isSeed ? path.resolve(srcDir, 'db/seeders') : path.resolve(srcDir, 'db/migrations')

// Convert Windows backslashes to forward slashes for glob pattern
const globPath = baseDir.replace(/\\/g, '/') + '/*.{ts,js}'

const umzug = new Umzug({
context: {
Expand All @@ -65,7 +70,7 @@ const umzug = new Umzug({
storage: new SequelizeStorage({ sequelize }),

migrations: {
glob: path.join(baseDir, '*.{ts,js}'),
glob: globPath,

resolve: ({ name, path: filePath, context }) => {
if (!filePath) {
Expand Down
4 changes: 4 additions & 0 deletions src/models/planSchema.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module.exports = (sequelize, DataTypes) => {
const PlanSchema = sequelize.define('PlanSchema', {
plan: {
type: DataTypes.STRING,
allowNull: false
},
name: DataTypes.STRING,
description: DataTypes.STRING,
fee: DataTypes.DECIMAL,
Expand Down
10 changes: 9 additions & 1 deletion src/modules/orders/orderAuthorize.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Promise = require('bluebird')
const requestPromise = require('request-promise')
const models = require('../../models')
const comment = require('../bot/comment')
const slack = require('../shared/slack')

module.exports = Promise.method(function orderAuthorize(orderParameters) {
return requestPromise({
Expand Down Expand Up @@ -59,10 +60,17 @@ module.exports = Promise.method(function orderAuthorize(orderParameters) {
return Promise.all([
models.User.findByPk(orderData.userId),
models.Task.findByPk(orderData.TaskId)
]).spread((user, task) => {
]).then(async ([user, task]) => {
if (orderData.paid) {
comment(orderData, task)
PaymentMail.success(user, task, orderData.amount)

// Send Slack notification for PayPal payment completion
const orderDataForNotification = {
amount: orderData.amount,
currency: orderData.currency || 'USD'
}
await slack.notifyBounty(task, orderDataForNotification, user, 'PayPal payment')
} else {
PaymentMail.error(user.dataValues, task, orderData.amount)
}
Expand Down
Loading