Merge branch 'master' of https://gitlab.com/fyipe-project/app into performancemonitor

This commit is contained in:
deityhub
2021-04-23 09:26:32 +01:00
44 changed files with 31913 additions and 42240 deletions

View File

@@ -8,6 +8,7 @@ const express = require('express');
const router = express.Router();
const SubscriberService = require('../services/subscriberService');
const MonitorService = require('../services/monitorService');
const getUser = require('../middlewares/user').getUser;
@@ -333,6 +334,50 @@ router.get('/:projectId/monitor/:monitorId', async function(req, res) {
}
});
//get monitors by subscriberId
// req.params-> {subscriberId};
// Returns: response subscriber, error message
router.get('/monitorList/:subscriberId', async function(req, res) {
try {
const subscriberId = req.params.subscriberId;
const subscriber = await SubscriberService.findBy({
_id: subscriberId,
});
const subscriptions = await SubscriberService.findBy({
contactEmail: subscriber[0].contactEmail,
subscribed: true,
});
const monitorIds = subscriptions.map(
subscription => subscription.monitorId
);
const subscriberMonitors = await MonitorService.findBy({
_id: { $in: monitorIds },
deleted: false,
});
const filteredSubscriptions = [];
subscriptions.map(subscription => {
subscriberMonitors.map(subscriberMonitor => {
if (
String(subscription.monitorId) ===
String(subscriberMonitor._id)
) {
filteredSubscriptions.push(subscription);
}
});
});
return sendListResponse(req, res, filteredSubscriptions);
} catch (error) {
return sendErrorResponse(req, res, error);
}
});
//Get a subscriber.
//req.params-> {projectId, subscriberId}
// Returns: response subscriber, error message
@@ -350,14 +395,14 @@ router.get('/:projectId/:subscriberId', async function(req, res) {
}
});
//Get a subscriber.
//unsubscribe subscriber.
//req.params-> {monitorId, subscriberId}
// Returns: response subscriber, error message
router.put('/unsubscribe/:monitorId/:subscriberId', async function(req, res) {
router.put('/unsubscribe/:monitorId/:email', async function(req, res) {
try {
const { subscriberId, monitorId } = req.params;
const { email, monitorId } = req.params;
const subscriber = await SubscriberService.updateOneBy(
{ _id: subscriberId, monitorId },
{ monitorId, contactEmail: email },
{ subscribed: false }
);
return sendItemResponse(req, res, subscriber);

View File

@@ -2033,7 +2033,10 @@ body[override] table.st-Button td.st-Button-area span.st-Button-internal{
'{{monitorName}} : Name of the monitor on which the event was created.',
'{{userId}} : Unique identifier for user account.',
'{{projectId}} : Unique identifier for the current project.',
'{{unsubscribeUrl}} : URL to unsubscribe from the monitor',
'{{resourcesAffected}} : List of monitors affected by scheduled maintenance event',
],
emailType: 'Subscriber Scheduled Maintenance',
subject: `New Scheduled Maintenance Event for {{projectName}} - {{eventName}}`,
body: `
@@ -2324,7 +2327,7 @@ body[override] table.st-Button td.st-Button-area span.st-Button-internal{
</td>
</tr>
<td class="st-Spacer st-Spacer--gutter" style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;" width="64">
<div class="st-Spacer st-Spacer--filler"></div>
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tbody>
</table>
@@ -2351,14 +2354,22 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Event Name: </strong>
<span>{{eventName}}</span><br></p>
{{#if eventDescription}}
<p style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Resource Affected: </strong>
<span>{{resourcesAffected}}</span><br></p>
{{/if}}
{{#if eventDescription}}
<p
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Description:</strong> <span>{{eventDescription}}</span><br></p>
{{/if}}
<p
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Start time: </strong> <span>{{eventStartTime}}</span><br></p>
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Start time: </strong> <span>{{eventStartTime}}</span><br></p>
<p
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>End time: </strong> <span>{{eventEndTime}}</span><br></p>
@@ -2503,7 +2514,7 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
</td>
<td class="st-Font st-Font--caption" style="border: 0; margin: 0;padding: 0; color: #8898aa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; line-height: 16px;">
<span class="st-Delink st-Delink--footer" style="border: 0; margin: 0; padding: 0; color: #8898aa; text-decoration: none;">
© {{year}} HackerBay Inc.
© {{year}} HackerBay Inc. | <span><a href={{unsubscribeUrl}}>Unsubscribe</a></span>
</span>
</td>
<td class="st-Spacer st-Spacer--gutter" style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;" width="64">
@@ -2555,6 +2566,8 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
'{{content}} : Content of created note.',
'{{projectName}} : Name of the project on which the event was created.',
'{{monitorName}} : Name of the monitor on which the event was created.',
'{{unsubscribeUrl}} : URL to unsubscribe from the monitor',
'{{resourcesAffected}} : List of monitors affected by scheduled maintenance event',
],
emailType: 'Subscriber Scheduled Maintenance Note',
subject: `New Scheduled Maintenance Event Note for {{projectName}} - {{eventName}} `,
@@ -2874,7 +2887,14 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
<p
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Note: </strong> "<span>{{content}}</span>"<br></p>
<strong>Note: </strong> "<span>{{content}}</span>"<br></p>
{{#if resourcesAffected}}
<p style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Resource Affected: </strong>
<span>{{resourcesAffected}}</span><br></p>
{{/if}}
</td>
</tr>
</tbody>
@@ -3015,7 +3035,7 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
</td>
<td class="st-Font st-Font--caption" style="border: 0; margin: 0;padding: 0; color: #8898aa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; line-height: 16px;">
<span class="st-Delink st-Delink--footer" style="border: 0; margin: 0; padding: 0; color: #8898aa; text-decoration: none;">
© {{year}} HackerBay Inc.
© {{year}} HackerBay Inc. | <span><a href={{unsubscribeUrl}}>Unsubscribe</a></span>
</span>
</td>
<td class="st-Spacer st-Spacer--gutter" style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;" width="64">
@@ -3067,6 +3087,8 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
'{{eventResolveTime}} : Time at which scheduled event is created.',
'{{projectName}} : Name of the project on which the event was created.',
'{{monitorName}} : Name of the monitor on which the event was created.',
'{{unsubscribeUrl}} : URL to unsubscribe from the monitor',
'{{resourcesAffected}} : List of monitors affected by scheduled maintenance event',
],
emailType: 'Subscriber Scheduled Maintenance Resolved',
subject: `Resolved Scheduled Maintenance Event for {{projectName}} - {{eventName}}`,
@@ -3380,6 +3402,11 @@ width="500" style="min-width: 500px;margin: 40px 50px;">
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Event Name: </strong>
<span>{{eventName}}</span><br></p>
{{#if resourcesAffected}}
<p style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Resource Affected: </strong>
<span>{{resourcesAffected}}</span><br></p>
{{/if}}
<p
style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<strong>Resolved at:</strong> <span>{{eventResolveTime}}</span><br></p>
@@ -3520,7 +3547,7 @@ You are receiving this mail because you are subscribed to this monitor.
</td>
<td class="st-Font st-Font--caption" style="border: 0; margin: 0;padding: 0; color: #8898aa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; line-height: 16px;">
<span class="st-Delink st-Delink--footer" style="border: 0; margin: 0; padding: 0; color: #8898aa; text-decoration: none;">
© {{year}} HackerBay Inc.
© {{year}} HackerBay Inc. | <span><a href={{unsubscribeUrl}}>Unsubscribe</a></span>
</span>
</td>
<td class="st-Spacer st-Spacer--gutter" style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;" width="64">

View File

@@ -3448,6 +3448,7 @@ module.exports = {
const subscribers = await SubscriberService.subscribersForAlert(
{
monitorId: monitor.monitorId._id,
subscribed: true,
}
);
@@ -3481,6 +3482,7 @@ module.exports = {
const subscribers = await SubscriberService.subscribersForAlert(
{
monitorId: monitor.monitorId._id,
subscribed: true,
}
);
@@ -3508,11 +3510,24 @@ module.exports = {
try {
const _this = this;
const uuid = new Date().getTime();
const monitorIds =
message.scheduledEventId &&
message.scheduledEventId.monitors.map(
monitor => monitor.monitorId
);
const monitorsAffected = await MonitorService.findBy({
_id: { $in: monitorIds },
deleted: false,
});
if (message) {
for (const monitor of message.scheduledEventId.monitors) {
const subscribers = await SubscriberService.subscribersForAlert(
{
monitorId: monitor.monitorId._id,
subscribed: true,
}
);
const totalSubscribers = subscribers.length;
@@ -3525,6 +3540,8 @@ module.exports = {
_id: projectId,
});
const unsubscribeUrl = `${global.homeHost}/unsubscribe/${subscriber.monitorId}/${subscriber._id}`;
if (subscriber.alertVia === AlertType.Email) {
const hasGlobalSmtpSettings = await GlobalConfigService.findOneBy(
{
@@ -3627,7 +3644,9 @@ module.exports = {
replyAddress,
project.name,
monitor.name,
projectId
projectId,
unsubscribeUrl,
monitorsAffected
);
alertStatus = 'Sent';
await SubscriberAlertService.updateOneBy(
@@ -3991,6 +4010,7 @@ module.exports = {
id,
});
const alertId = subscriberAlert._id;
const unsubscribeUrl = `${global.homeHost}/unsubscribe/${subscriber.monitorId}/${subscriber._id}`;
let alertStatus = null;
try {
@@ -4005,7 +4025,8 @@ module.exports = {
projectName,
emailTemplate,
componentName,
project.replyAddress
project.replyAddress,
unsubscribeUrl
);
alertStatus = 'Sent';
@@ -4023,7 +4044,8 @@ module.exports = {
projectName,
emailTemplate,
componentName,
project.replyAddress
project.replyAddress,
unsubscribeUrl
);
alertStatus = 'Sent';

View File

@@ -3864,7 +3864,8 @@ const _this = {
projectName,
emailTemplate,
componentName,
replyAddress
replyAddress,
unsubscribeUrl
) {
let mailOptions = {};
let EmailBody;
@@ -3876,7 +3877,11 @@ const _this = {
'Subscriber Scheduled Maintenance'
);
//project name
const resourcesAffected = [];
schedule.monitors.map(monitor => {
resourcesAffected.push(monitor.monitorId.name);
});
const data = {
scheduledTime,
monitorName,
@@ -3890,6 +3895,8 @@ const _this = {
eventCreateTime: schedule.createdAt,
eventStartTime: schedule.startDate,
eventEndTime: schedule.endDate,
resourcesAffected: resourcesAffected.toString(),
unsubscribeUrl,
year: DateTime.getCurrentYear,
};
template = template(data);
@@ -4073,7 +4080,8 @@ const _this = {
projectName,
emailTemplate,
componentName,
replyAddress
replyAddress,
unsubscribeUrl
) {
let mailOptions = {};
let EmailBody;
@@ -4085,6 +4093,10 @@ const _this = {
'Subscriber Scheduled Maintenance Resolved'
);
const resourcesAffected = [];
schedule.monitors.map(monitor => {
resourcesAffected.push(monitor.monitorId.name);
});
//project name
const data = {
scheduledTime,
@@ -4096,6 +4108,8 @@ const _this = {
componentName,
eventName: schedule.name,
eventResolveTime: schedule.resolvedAt,
unsubscribeUrl,
resourcesAffected: resourcesAffected.toString(),
year: DateTime.getCurrentYear,
};
template = template(data);
@@ -4280,12 +4294,19 @@ const _this = {
replyAddress,
projectName,
monitorName,
projectId
projectId,
unsubscribeUrl,
monitorsAffected
) {
let mailOptions = {};
let EmailBody;
let smtpServer;
const resourcesAffected = [];
monitorsAffected.map(monitor => {
resourcesAffected.push(monitor.name);
});
const capitalizeStatus =
status.charAt(0).toUpperCase() + status.slice(1);
@@ -4304,6 +4325,8 @@ const _this = {
content,
projectName,
monitorName,
unsubscribeUrl,
resourcesAffected: resourcesAffected.toString(),
year: DateTime.getCurrentYear,
};
template = template(data);

View File

@@ -13,7 +13,7 @@ module.exports = {
.populate('scheduledEventId', 'name')
.populate({
path: 'scheduledEventId',
select: 'name monitors',
select: 'name monitors alertSubscriber',
populate: {
path: 'projectId',
select: 'name replyAddress',
@@ -21,8 +21,8 @@ module.exports = {
})
.populate('createdById', 'name')
.execPopulate();
if (
scheduledEventMessage.scheduledEventId.alertSubscriber &&
scheduledEventMessage.type === 'investigation' &&
!(
scheduledEventMessage.event_state === 'Resolved' ||

View File

@@ -105,7 +105,7 @@ module.exports = {
.limit(limit)
.skip(skip)
.populate('projectId')
.populate('monitorId')
.populate('monitorId', 'name')
.populate('statusPageId');
const subscribersArr = [];

View File

@@ -23,7 +23,7 @@ const EmailSmtpService = require('../backend/services/emailSmtpService');
const VerificationTokenModel = require('../backend/models/verificationToken');
let token, userId, projectId, monitorId, incidentId, subscriberId;
let token, userId, projectId, monitorId, incidentId, subscriberId, idNumber;
const monitor = {
name: 'New Monitor',
type: 'url',
@@ -73,6 +73,7 @@ describe('Subcriber Alert API', function() {
)
.send(incidentData)
.end((err, res) => {
idNumber = res.body.idNumber; // This has replaced incidentId and is used to query subscriber alert
incidentId = res.body._id;
expect(res).to.have.status(
200
@@ -130,7 +131,7 @@ describe('Subcriber Alert API', function() {
alertVia: 'email',
contactEmail: userData.user.email,
})
.end((err, res) => {
.end((err, res) => {
subscriberId = res.body._id;
request
.post(
@@ -141,7 +142,7 @@ describe('Subcriber Alert API', function() {
alertVia: 'email',
eventType: 'identified',
})
.end((err, res) => {
.end((err, res) => {
expect(res).to.have.status(200);
expect(res.body).to.be.an('object');
expect(res.body.alertVia).to.be.equal(
@@ -173,7 +174,7 @@ describe('Subcriber Alert API', function() {
});
it('should get subscriber alerts by projectId', done => {
request.get(`/subscriberAlert/${projectId}`).end((err, res) => {
request.get(`/subscriberAlert/${projectId}`).end((err, res) => {
expect(res).to.have.status(200);
expect(res.body).to.be.an('object');
expect(res.body).to.have.property('data');
@@ -184,7 +185,7 @@ describe('Subcriber Alert API', function() {
it('should get subscriber alerts by incidentId', done => {
request
.get(`/subscriberAlert/${projectId}/incident/${incidentId}`)
.get(`/subscriberAlert/${projectId}/incident/${idNumber}`)
.end((err, res) => {
expect(res).to.have.status(200);
expect(res.body).to.be.an('object');

View File

@@ -1,5 +1,5 @@
## DEPLOYMENT STAGE - fyipe-acme-http-01
deploy_fyipe-acme-http-01:
## DEPLOYMENT STAGE FOR STAGING - fyipe-acme-http-01-staging
deploy_staging_fyipe-acme-http-01:
stage: Deploy
allow_failure: true
retry: 2
@@ -9,9 +9,11 @@ deploy_fyipe-acme-http-01:
- sudo apt-get install -y build-essential
- curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
- sudo apt-get install -y nodejs
- sudo npm install -g json
- cd fyipe-acme-http-01
- chmod +x ../ci/scripts/version-setup.sh
- ../ci/scripts/version-setup.sh
- json -I -f package.json -e 'this.name="fyipe-acme-http-01-staging"'
- echo "//registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN" > ~/.npmrc
- npm publish
- cd ..
@@ -20,6 +22,34 @@ deploy_fyipe-acme-http-01:
only:
refs:
- master
- release
- hotfix-master
environment:
name: staging
## DEPLOYMENT STAGE FOR PRODUCTION - fyipe-acme-http-01
deploy_production_fyipe-acme-http-01:
stage: Deploy
allow_failure: true
retry: 2
script:
- sudo apt-get update
- sudo apt-get install -y curl gcc
- sudo apt-get install -y build-essential
- curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
- sudo apt-get install -y nodejs
- sudo npm install -g json
- cd fyipe-acme-http-01
- chmod +x ../ci/scripts/version-setup.sh
- ../ci/scripts/version-setup.sh
- json -I -f package.json -e 'this.name="fyipe-acme-http-01"'
- echo "//registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN" > ~/.npmrc
- npm publish
- cd ..
- chmod +x ./ci/scripts/cleanup.sh
- ./ci/scripts/cleanup.sh
only:
refs:
- release
- hotfix-release
environment:
name: production

View File

@@ -1,5 +1,5 @@
## DEPLOYMENT STAGE - fyipe-le-store
deploy_fyipe-le-store:
## DEPLOYMENT STAGE FOR STAGING - fyipe-le-store-staging
deploy_staging_fyipe-le-store:
stage: Deploy
allow_failure: true
retry: 2
@@ -9,9 +9,11 @@ deploy_fyipe-le-store:
- sudo apt-get install -y build-essential
- curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
- sudo apt-get install -y nodejs
- sudo npm install -g json
- cd fyipe-le-store
- chmod +x ../ci/scripts/version-setup.sh
- ../ci/scripts/version-setup.sh
- json -I -f package.json -e 'this.name="fyipe-le-store-staging"'
- echo "//registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN" > ~/.npmrc
- npm publish
- cd ..
@@ -20,6 +22,34 @@ deploy_fyipe-le-store:
only:
refs:
- master
- release
- hotfix-master
environment:
name: staging
## DEPLOYMENT STAGE FOR PRODUCTION - fyipe-le-store
deploy_production_fyipe-le-store:
stage: Deploy
allow_failure: true
retry: 2
script:
- sudo apt-get update
- sudo apt-get install -y curl gcc
- sudo apt-get install -y build-essential
- curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
- sudo apt-get install -y nodejs
- sudo npm install -g json
- cd fyipe-le-store
- chmod +x ../ci/scripts/version-setup.sh
- ../ci/scripts/version-setup.sh
- json -I -f package.json -e 'this.name="fyipe-le-store"'
- echo "//registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN" > ~/.npmrc
- npm publish
- cd ..
- chmod +x ./ci/scripts/cleanup.sh
- ./ci/scripts/cleanup.sh
only:
refs:
- release
- hotfix-release
environment:
name: production

72161
dashboard/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -106,7 +106,7 @@
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"depcheck": "^1.3.1",
"fyipe-server-monitor": "^3.0.8980",
"fyipe": "^3.0.10051",
"jest-localstorage-mock": "^2.2.0",
"npm-force-resolutions": "0.0.3",
"redux-mock-store": "^1.5.3",

View File

@@ -35255,6 +35255,9 @@ padding-left:20px
align-items: center;
height: 200px;
}
.bs-type-status .Box-root {
margin-top: 0px !important;
}
@media (max-width: 768px) {
.bs-thread-container {
margin-top: 20px

View File

@@ -17,10 +17,14 @@ import { RenderField } from '../basic/RenderField';
import { RenderSelect } from '../basic/RenderSelect';
import { fetchMonitorsSubscribers } from '../../actions/monitor';
import countryCodes from '../../utils/countryCodes';
import { fetchStatusPageSubscribers } from '../../actions/statusPage';
function validate(values) {
const errors = {};
if (!Validate.text(values.monitorId)) {
errors.monitorId = 'Please select a monitor.';
}
if (!Validate.text(values.alertVia)) {
errors.alertVia = 'Please select a subscribe method.';
} else {
@@ -88,11 +92,23 @@ class CreateSubscriber extends Component {
closeThisDialog,
data,
fetchMonitorsSubscribers,
fetchStatusPageSubscribers,
} = this.props;
const { monitorId, subProjectId } = data;
createSubscriber(subProjectId, monitorId, values).then(
const { monitorId, subProjectId, statusPage, limit } = data;
createSubscriber(
subProjectId,
monitorId ?? values.monitorId,
values
).then(
function() {
fetchMonitorsSubscribers(subProjectId, monitorId, 0, 5);
statusPage
? fetchStatusPageSubscribers(
subProjectId,
statusPage._id,
0,
limit
)
: fetchMonitorsSubscribers(subProjectId, monitorId, 0, 5);
closeThisDialog();
},
function() {
@@ -113,7 +129,19 @@ class CreateSubscriber extends Component {
};
render() {
const { handleSubmit, closeThisDialog } = this.props;
const { handleSubmit, closeThisDialog, data } = this.props;
let monitorsList;
if (data && data.monitorList && data.monitorList.length > 0) {
monitorsList = data.monitorList.map(monitor => ({
value: monitor.monitor,
label: monitor.monitorName,
}));
monitorsList.unshift({
value: '',
label: 'Select a monitor',
});
}
return (
<div
@@ -142,7 +170,7 @@ class CreateSubscriber extends Component {
<div className="bs-Modal-block bs-u-paddingless">
<div className="bs-Modal-content">
<span className="bs-Fieldset">
<div className="bs-Fieldset-row">
<div className="bs-Fieldset-row bs-type-status">
<label className="bs-Fieldset-label">
Alert Via
</label>
@@ -333,6 +361,33 @@ class CreateSubscriber extends Component {
</div>
</div>
)}
<ShouldRender
if={
data.monitorList &&
data.monitorList
.length > 0
}
>
<div className="bs-Fieldset-row">
<label className="bs-Fieldset-label">
Monitor
</label>
<div className="bs-Fieldset-fields bs-type-status">
<Field
className="db-select-nw"
component={
RenderSelect
}
name="monitorId"
id="monitorId"
required="required"
options={
monitorsList
}
/>
</div>
</div>
</ShouldRender>
</span>
</div>
</div>
@@ -433,6 +488,7 @@ const mapDispatchToProps = dispatch => {
createSubscriberSuccess,
createSubscriber,
fetchMonitorsSubscribers,
fetchStatusPageSubscribers,
},
dispatch
);
@@ -452,12 +508,14 @@ CreateSubscriber.propTypes = {
createSubscriber: PropTypes.func.isRequired,
handleSubmit: PropTypes.func,
fetchMonitorsSubscribers: PropTypes.func,
fetchStatusPageSubscribers: PropTypes.func,
newSubscriber: PropTypes.object,
error: PropTypes.object,
requesting: PropTypes.bool,
type: PropTypes.string,
data: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
createSubscriberError: PropTypes.func,
monitorList: PropTypes.array,
};
export default connect(

View File

@@ -8,9 +8,7 @@ import moment from 'moment';
import ShouldRender from '../basic/ShouldRender';
import { openModal } from '../../actions/modal';
import CreateSchedule from '../modals/CreateSchedule';
import EditSchedule from '../modals/EditSchedule';
import DataPathHoC from '../DataPathHoC';
import DeleteSchedule from '../modals/DeleteSchedule';
import { history } from '../../store';
import { capitalize } from '../../config';
import { ListLoader } from '../basic/Loader';
@@ -88,11 +86,9 @@ class EventBox extends Component {
limit,
count,
skip,
profileSettings,
error,
requesting,
projectId,
openModal,
fetchingMonitors,
monitors,
currentProject,
@@ -306,12 +302,6 @@ class EventBox extends Component {
).format(
'MMMM Do YYYY, h:mm a'
)}
<br />
<strong>
{
profileSettings.timezone
}
</strong>
</div>
</div>
<div className="bs-ObjectList-cell bs-u-v-middle">
@@ -321,12 +311,6 @@ class EventBox extends Component {
).format(
'MMMM Do YYYY, h:mm a'
)}
<br />
<strong>
{
profileSettings.timezone
}
</strong>
</div>
</div>
<div className="bs-ObjectList-cell bs-u-v-middle">
@@ -336,6 +320,12 @@ class EventBox extends Component {
title="view"
className="bs-Button bs-DeprecatedButton"
type="button"
style={{
float:
'right',
marginRight:
'10px',
}}
onClick={e => {
e.preventDefault();
e.stopPropagation();
@@ -348,59 +338,6 @@ class EventBox extends Component {
View
</span>
</button>
<button
id={`editCredentialBtn_${index}`}
title="edit"
className="bs-Button bs-DeprecatedButton db-Trends-editButton bs-Button--icon bs-Button--edit"
style={{
marginLeft: 20,
}}
type="button"
onClick={e => {
e.preventDefault();
e.stopPropagation();
openModal({
id: createScheduledEventModalId,
content: EditSchedule,
event: scheduledEvent,
projectId,
});
}}
>
<span>
Edit
</span>
</button>
<button
id={`deleteCredentialBtn_${index}`}
title="delete"
className="bs-Button bs-DeprecatedButton db-Trends-editButton bs-Button--icon bs-Button--delete"
style={{
marginLeft: 20,
}}
type="button"
onClick={e => {
e.preventDefault();
e.stopPropagation();
openModal({
id:
scheduledEvent._id,
content: DataPathHoC(
DeleteSchedule,
{
projectId,
parentProjectId,
eventId:
scheduledEvent._id,
}
),
});
}}
>
<span>
Delete
</span>
</button>
</div>
</div>
</div>

View File

@@ -121,6 +121,29 @@ export class Plans extends Component {
<div className="Box-root Margin-bottom--12">
<div className="bs-ContentSection Card-root Card-shadow--medium">
<div className="Box-root">
<div
className="Padding-horizontal--20 Padding-vertical--16 Flex-justifyContent--flexStart"
style={{ paddingBottom: '5px' }}
>
<ShouldRender if={isRequestingTrial}>
<ListLoader
style={{ textAlign: 'left' }}
/>
</ShouldRender>
<ShouldRender
if={!isRequesting && trialEndDate}
>
<div className="Badge Badge--color--blue Box-background--red bg-red-700 Box-root Flex-inlineFlex Flex-alignItems--center Padding-horizontal--8 Padding-vertical--2">
<span className="Badge-text bg-red-700 Text-display--inline Text-fontSize--12 Text-fontWeight--bold Text-lineHeight--16 Text-typeface--upper Text-wrap--noWrap">
<span className="Text-color--white">
Trial period (
{trialLeft} days left)
</span>
</span>
</div>
</ShouldRender>
</div>
<div className="bs-ContentSection-content Box-root Box-divider--surface-bottom-1 Flex-flex Flex-alignItems--center Flex-justifyContent--spaceBetween Padding-horizontal--20 Padding-vertical--16">
<div className="Box-root">
<span className="Text-color--inherit Text-display--inline Text-fontSize--16 Text-fontWeight--medium Text-lineHeight--24 Text-typeface--base Text-wrap--wrap">
@@ -166,39 +189,6 @@ export class Plans extends Component {
</div>
</div>
<div className="bs-ContentSection-content Box-root Box-background--offset Box-divider--surface-bottom-1 Padding-horizontal--8 Padding-vertical--2">
<div
className="bs-Fieldset-wrapper Box-root"
style={{
display: 'flex',
justifyContent: 'flex-end',
}}
>
<ShouldRender
if={isRequestingTrial}
>
<ListLoader />
</ShouldRender>
<ShouldRender
if={
!isRequesting &&
trialEndDate
}
>
<p className="Margin-all--16 bs-Button bs-Button--blue Badge">
<strong
style={{
fontSize: '17px',
fontWeight: '900',
}}
>
Trial period (
{trialLeft} days left)
</strong>
</p>
</ShouldRender>
</div>
<div>
<div className="bs-Fieldset-wrapper Box-root Margin-bottom--2">
<fieldset className="bs-Fieldset">

View File

@@ -10,12 +10,14 @@ import { FormLoader2, ListLoader } from '../basic/Loader';
import { v4 as uuidv4 } from 'uuid';
import DeleteSubscriber from '../../components/modals/DeleteComponent';
import DataPathHoC from '../DataPathHoC';
import { openModal } from '../../actions/modal';
import { openModal, closeModal } from '../../actions/modal';
import { deleteSubscriber } from '../../actions/subscriber';
import CreateSubscriber from '../modals/CreateSubscriber';
class StatusPageSubscriber extends Component {
constructor(props) {
super(props);
this.state = {
createSubscriberModalId: uuidv4(),
deleteSubscriberModalId: uuidv4(),
limit: 10,
};
@@ -90,8 +92,12 @@ class StatusPageSubscriber extends Component {
projectId,
subProjects,
currentProject,
monitors,
statusPage,
} = this.props;
const { createSubscriberModalId, limit } = this.state;
if (
subscribers &&
subscribers.skip &&
@@ -139,6 +145,37 @@ class StatusPageSubscriber extends Component {
on this Status Page.
</span>
</div>
<ShouldRender if={monitors && monitors.length > 0}>
<div className="ContentHeader-end Box-root Flex-flex Flex-alignItems--center Margin-left--16">
<button
className="bs-Button bs-ButtonLegacy ActionIconParent"
type="button"
id="addSubscriberButton"
onClick={() =>
this.props.openModal({
id: createSubscriberModalId,
onClose: () =>
this.props.closeModal({
id: createSubscriberModalId,
}),
content: DataPathHoC(
CreateSubscriber,
{
subProjectId: projectId,
monitorList: monitors,
statusPage,
limit,
}
),
})
}
>
<span className="bs-FileUploadButton bs-Button--icon bs-Button--new">
<span>Add New Subscriber</span>
</span>
</button>
</div>
</ShouldRender>
</div>
</div>
</div>
@@ -573,11 +610,12 @@ StatusPageSubscriber.displayName = 'StatusPageSubscriber';
const mapStateToProps = state => ({
subscribers: state.statusPage.subscribers,
monitors: state.statusPage.status.monitors,
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{ fetchStatusPageSubscribers, openModal, deleteSubscriber },
{ fetchStatusPageSubscribers, openModal, closeModal, deleteSubscriber },
dispatch
);
@@ -586,10 +624,12 @@ StatusPageSubscriber.propTypes = {
subscribers: PropTypes.object,
projectId: PropTypes.string,
openModal: PropTypes.func,
closeModal: PropTypes.func,
deleteSubscriber: PropTypes.func,
currentProject: PropTypes.object,
subProjects: PropTypes.array,
statusPage: PropTypes.object,
monitors: PropTypes.array,
};
export default connect(

View File

@@ -955,6 +955,7 @@ export default function statusPage(state = INITIAL_STATE, action) {
monitors.push({
...monitorData,
monitor: monitorData.monitor._id,
monitorName: monitorData.monitor.name,
});
});
statusPages.push({

View File

@@ -7,9 +7,10 @@ axios.defaults.adapter = require('axios/lib/adapters/http');
let serverMonitor;
try {
// try to use local package (with recent changes)
serverMonitor = require('../../../../server-monitor/lib/api');
serverMonitor = require('../../../../js-sdk/src/cli/server-monitor/lib/api');
} catch (error) {
serverMonitor = require('fyipe-server-monitor');
const fyipe = require('fyipe');
serverMonitor = fyipe.ServerMonitor;
}
require('should');

View File

@@ -4,22 +4,28 @@
# This only runs on Linux (Ubuntu) and not on MacOS
###
HELM_RELEASE_NAME='fi'
# IP of the mongodb servers.
MONGO_PRIMARY_SERVER_IP='167.172.15.25'
MONGO_SECONDARY_SERVER_IP='157.230.66.225'
MONGO_SERVER_PORT="80"
FYIPE_DB_USERNAME='fyipe'
FYIPE_DB_PASSWORD='password'
FYIPE_DB_NAME='fyipedb'
CURRENT_DATE=$(date +%s)
CURRENT_USER=$(whoami)
BACKUP_PATH=~/db-backup
BACKUP_RETAIN_DAYS=14
BACKUP_RETAIN_DAYS=2
TODAY=`date +"%d%b%Y"`
red=`tput setaf 1`
green=`tput setaf 2`
reset=`tput sgr 0`
# Delete all the monitor logs before 3 months before taking the backup.
THREE_MONTHS_AGO=$(date -d "-120 days")
# Delete all the monitor logs before 3 days before taking the backup.
THREE_DAYS_AGO=$(date -d "-3 days" +"%Y-%m-%d")
THREE_MONTHS_AGO=$(date -d "-120 days" +"%Y-%m-%d")
SIX_MONTHS_AGO=$(date -d "-180 days" +"%Y-%m-%d")
function HELP (){
echo ""
@@ -43,8 +49,6 @@ function HELP (){
# PASS IN ARGUMENTS
while getopts ":r:u:p:n:l:t:h" opt; do
case $opt in
r) HELM_RELEASE_NAME="$OPTARG"
;;
u) FYIPE_DB_USERNAME="$OPTARG"
;;
p) FYIPE_DB_PASSWORD="$OPTARG"
@@ -76,11 +80,6 @@ function BACKUP_SUCCESS(){
"text": {
"type": "mrkdwn",
"text": "*Backup complete*\n Date:'${TODAY}'\nPath: '$BACKUP_PATH'/fyipe-backup-'$CURRENT_DATE'.archive"
},
"accessory": {
"type": "image",
"image_url":"https://www.fonedog.com/images/backup-restore/ios/what-does-restore-from-backup-mean.jpg",
"alt_text": "alt text for image"
}
},
{
@@ -101,11 +100,6 @@ function BACKUP_FAIL_SERVER(){
"text": {
"type": "mrkdwn",
"text": "*Backup Failed*\n Date:'${TODAY}'\nReason: Could not create backup on container.\nPath: '$BACKUP_PATH'/fyipe-backup-'$CURRENT_DATE'.archive"
},
"accessory": {
"type": "image",
"image_url":"https://www.fonedog.com/images/backup-restore/ios/what-does-restore-from-backup-mean.jpg",
"alt_text": "alt text for image"
}
},
{
@@ -126,11 +120,6 @@ function BACKUP_FAIL_LOCAL(){
"text": {
"type": "mrkdwn",
"text": "*Backup failed*\n Date:'${TODAY}'\nReason: Could not create backup on local path.\nPath: '$BACKUP_PATH'/fyipe-backup-'$CURRENT_DATE'.archive"
},
"accessory": {
"type": "image",
"image_url":"https://www.fonedog.com/images/backup-restore/ios/what-does-restore-from-backup-mean.jpg",
"alt_text": "alt text for image"
}
},
{
@@ -146,31 +135,25 @@ echo ""
# Drop audit logs collection because we dont need to take backup of that.
echo "Removing audit logs collections. This will take some time."
sudo kubectl exec fi-mongodb-primary-0 -- mongo fyipedb --username $FYIPE_DB_USERNAME --password $FYIPE_DB_PASSWORD --eval 'db.auditlogs.drop()'
sudo mongo ${FYIPE_DB_NAME} --host="${MONGO_PRIMARY_SERVER_IP}" --port="${MONGO_SERVER_PORT}" --username="$FYIPE_DB_USERNAME" --password="$FYIPE_DB_PASSWORD" --eval 'db.auditlogs.drop()'
# Remove all the monitor logs which are more than 120 days old to make backups faster.
# Remove old monitor logs to make backup faster
echo "Removing old monitor logs. This will take some time."
sudo kubectl exec fi-mongodb-primary-0 -- mongo fyipedb --username $FYIPE_DB_USERNAME --password $FYIPE_DB_PASSWORD --eval 'db.monitorlogs.remove({"createdAt": { "$lt": new Date("$THREE_MONTHS_AGO")}})'
sudo mongo ${FYIPE_DB_NAME} --host="${MONGO_PRIMARY_SERVER_IP}" --port="${MONGO_SERVER_PORT}" --username="$FYIPE_DB_USERNAME" --password="$FYIPE_DB_PASSWORD" --eval "db.monitorlogs.remove({'createdAt': { \$lt: ISODate('${THREE_DAYS_AGO}')}})"
sudo mongo ${FYIPE_DB_NAME} --host="${MONGO_PRIMARY_SERVER_IP}" --port="${MONGO_SERVER_PORT}" --username="$FYIPE_DB_USERNAME" --password="$FYIPE_DB_PASSWORD" --eval "db.monitorlogbyweeks.remove({'createdAt': { \$lt: ISODate('${SIX_MONTHS_AGO}')}})"
sudo mongo ${FYIPE_DB_NAME} --host="${MONGO_PRIMARY_SERVER_IP}" --port="${MONGO_SERVER_PORT}" --username="$FYIPE_DB_USERNAME" --password="$FYIPE_DB_PASSWORD" --eval "db.monitorlogbydays.remove({'createdAt': { \$lt: ISODate('${THREE_MONTHS_AGO}')}})"
sudo mongo ${FYIPE_DB_NAME} --host="${MONGO_PRIMARY_SERVER_IP}" --port="${MONGO_SERVER_PORT}" --username="$FYIPE_DB_USERNAME" --password="$FYIPE_DB_PASSWORD" --eval "db.monitorlogbyhours.remove({'createdAt': { \$lt: ISODate('${THREE_MONTHS_AGO}')}})"
# Sleeping for 10 mins for database server to cool down.
sleep 10m
# Take backup from secondary and not from primary. This will not slow primary down.
if sudo kubectl exec fi-mongodb-secondary-0 -- mongodump --uri="mongodb://$FYIPE_DB_USERNAME:$FYIPE_DB_PASSWORD@localhost:27017/$FYIPE_DB_NAME" --archive="/tmp/fyipedata.archive"; then
echo "Copying backup from server to local computer. This will take some time...."
echo ""
if sudo kubectl cp fi-mongodb-secondary-0 :tmp/fyipedata.archive "$BACKUP_PATH/fyipe-backup-$CURRENT_DATE.archive"; then
echo ${green}"File Saved: $BACKUP_PATH/fyipe-backup-$CURRENT_DATE.archive"${reset}
echo ""
sudo kubectl exec fi-mongodb-secondary-0 -- rm tmp/fyipedata.archive
BACKUP_SUCCESS
else
echo ${red}"Failure, exit status: $?" ${reset}
BACKUP_FAIL_LOCAL
fi
if mongodump --forceTableScan --authenticationDatabase="${FYIPE_DB_NAME}" --host="${MONGO_SECONDARY_SERVER_IP}" --db="${FYIPE_DB_NAME}" --port="${MONGO_SERVER_PORT}" --username="${FYIPE_DB_USERNAME}" --password="${FYIPE_DB_PASSWORD}" --archive="$BACKUP_PATH/fyipe-backup-$CURRENT_DATE.archive"; then
echo ${green}"BACKUP SUCCESS $"${reset}
BACKUP_SUCCESS
else
echo ${red}"Failure, exit status: $"${reset}
BACKUP_FAIL_SERVER
echo ${red}"Failure, exit status: $"${reset}
BACKUP_FAIL_SERVER
fi
####### Remove backups older than {BACKUP_RETAIN_DAYS} days ########

View File

@@ -93,13 +93,18 @@ Persistent=true
WantedBy=timers.target
' > /etc/systemd/system/backup.timer
# STEP 6: make files.sh executable
chmod +x "$HOME"/backup.sh
# STEP 6: make files.sh executable
chmod +x "$HOME"/backup.sh
# STEP 7: Start timer
sudo systemctl daemon-reload
# STEP 7: Start timer
sudo systemctl daemon-reload
sudo systemctl enable backup.timer
sudo systemctl enable backup.timer
sudo systemctl start backup.timer
sudo systemctl start backup.timer
# Install Mongodb locally for mongo cli and mongodump and mongorestore.
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update
sudo apt-get install -y mongodb-org

View File

@@ -1,13 +1,17 @@
###
#
# Please make sure kubectl is installed nad context is pointed to the cluster you want to resotre to.
#
#
# RUN THIS BY:
# bash restore.sh -f <FILENAME>.archive
#
###
# Variables, please check these before you run the script.
HELM_RELEASE_NAME='fi'
MONGO_PRIMARY_SERVER_IP='167.172.15.25'
MONGO_SERVER_PORT="80"
FYIPE_DB_USERNAME='fyipe'
FYIPE_DB_PASSWORD='password'
FYIPE_DB_NAME='fyipedb'
@@ -37,8 +41,6 @@ function HELP (){
# PASS IN ARGUMENTS
while getopts ":r:u:p:n:l:f:h" opt; do
case $opt in
r) HELM_RELEASE_NAME="$OPTARG"
;;
u) FYIPE_DB_USERNAME="$OPTARG"
;;
p) FYIPE_DB_PASSWORD="$OPTARG"
@@ -72,11 +74,6 @@ function RESTORE_SUCCESS (){
"text": {
"type": "mrkdwn",
"text": "*Restore complete*\n Date:'${TODAY}'\nFile Name: '${FILE_NAME}'"
},
"accessory": {
"type": "image",
"image_url":"https://www.fonedog.com/images/backup-restore/ios/what-does-restore-from-backup-mean.jpg",
"alt_text": "alt text for image"
}
},
{
@@ -100,11 +97,6 @@ function RESTORE_FAIL_SERVER (){
"text": {
"type": "mrkdwn",
"text": "*Restore Failed*\n Date:'${TODAY}'\nReason: Could not restore database.\nFile Name: '${FILE_NAME}'"
},
"accessory": {
"type": "image",
"image_url":"https://www.fonedog.com/images/backup-restore/ios/what-does-restore-from-backup-mean.jpg",
"alt_text": "alt text for image"
}
},
{
@@ -129,11 +121,6 @@ function RESTORE_FAIL_LOCAL (){
"text": {
"type": "mrkdwn",
"text": "*Restore Failed*\n Date:'${TODAY}'\nReason: Could not copy backup to container.\nFile Name: '${FILE_NAME}'"
},
"accessory": {
"type": "image",
"image_url":"https://www.fonedog.com/images/backup-restore/ios/what-does-restore-from-backup-mean.jpg",
"alt_text": "alt text for image"
}
},
{
@@ -145,21 +132,14 @@ function RESTORE_FAIL_LOCAL (){
}
echo "Copying backup from local to server. This will take some time...."
echo "Restoring Database. This will take some time...."
echo ""
if sudo kubectl cp "$FILE_PATH/$FILE_NAME" fi-mongodb-primary-0:/tmp/fyipedata.archive; then
echo "Restoring a backup on the server."
echo ""
if kubectl exec fi-mongodb-primary-0 -- mongorestore --uri="mongodb://$FYIPE_DB_USERNAME:$FYIPE_DB_PASSWORD@localhost:27017/$FYIPE_DB_NAME" --archive="/tmp/fyipedata.archive"; then
echo "Restore success"
RESTORE_SUCCESS
else
echo "Restore Failed, exit status: $?"
RESTORE_FAIL_SERVER
fi
if mongorestore --authenticationDatabase="${FYIPE_DB_NAME}" --host="${MONGO_PRIMARY_SERVER_IP}" --db="${FYIPE_DB_NAME}" --port="${MONGO_SERVER_PORT}" --username="${FYIPE_DB_USERNAME}" --password="${FYIPE_DB_PASSWORD}" --archive="$FILE_PATH/$FILE_NAME"; then
echo "Restore success"
RESTORE_SUCCESS
else
echo "Restore Failed, exit status: $?"
RESTORE_FAIL_LOCAL
echo "Restore Failed, exit status: $?"
RESTORE_FAIL_SERVER
fi

View File

@@ -64,6 +64,18 @@ spec:
serviceName: {{ printf "%s-%s" $.Release.Name $probeKey }}
servicePort: 80
{{- end }}
{{- if $.Values.saas.isMongoSecondaryBackupServiceEnabled }}
- path: /mongo-secondary-backup
backend:
serviceName: {{ printf "%s-%s" $.Release.Name "mongo-secondary-backup" }}
servicePort: 80
{{- end }}
{{- if $.Values.saas.isMongoPrimaryBackupServiceEnabled }}
- path: /mongo-primary-backup
backend:
serviceName: {{ printf "%s-%s" $.Release.Name "mongo-primary-backup" }}
servicePort: 80
{{- end }}
{{- if $.Values.saas.isSaasService }}
- path: /
backend:

View File

@@ -0,0 +1,21 @@
{{- if .Values.saas.isMongoPrimaryBackupServiceEnabled }}
apiVersion: v1
kind: Service
metadata:
labels:
app: {{ printf "%s-%s" .Release.Name "mongo-primary-backup" }}
app.kubernetes.io/part-of: fyipe
app.kubernetes.io/managed-by: Helm
name: {{ printf "%s-%s" .Release.Name "mongo-primary-backup" }}
namespace: {{ .Release.Namespace }}
spec:
ports:
- port: 80
protocol: TCP
targetPort: 27017
selector:
app: mongodb
component: primary
type: LoadBalancer
---
{{- end }}

View File

@@ -0,0 +1,21 @@
{{- if .Values.saas.isMongoSecondaryBackupServiceEnabled }}
apiVersion: v1
kind: Service
metadata:
labels:
app: {{ printf "%s-%s" .Release.Name "mongo-secondary-backup" }}
app.kubernetes.io/part-of: fyipe
app.kubernetes.io/managed-by: Helm
name: {{ printf "%s-%s" .Release.Name "mongo-secondary-backup" }}
namespace: {{ .Release.Namespace }}
spec:
ports:
- port: 80
protocol: TCP
targetPort: 27017
selector:
app: mongodb
component: secondary
type: LoadBalancer
---
{{- end }}

View File

@@ -2,7 +2,9 @@
## Important: If you're implenting this in the enterprise environment, this should always be `false`.
## This is for Fyipe SaaS service. This will deploy all the SaaS env vars
##################################################################################
saas:
saas:
isMongoPrimaryBackupServiceEnabled: false
isMongoSecondaryBackupServiceEnabled: false
isSaasService: false
stripe:
publicKey: #Stripe public and private key

View File

@@ -1,3 +1,7 @@
User-agent: *
Disallow:
Disallow: /api/*
Disallow: /status-page/*
Disallow: /admin/*
Disallow: /haraka/*
Disallow: /dashboard/*
Sitemap: https://fyipe.com/sitemap.xml

View File

@@ -3,249 +3,254 @@
<url>
<loc>https://fyipe.com/</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>1.00</priority>
</url>
<url>
<loc>https://fyipe.com/pricing</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/support</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/status-page</loc>
<loc>https://fyipe.com/product/public-status-page</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/private-status-page</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
</url>
<url>
<loc>https://fyipe.com/product/uptime-monitoring</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/incident-management</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/app-security</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/api-monitoring</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/server-monitoring</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/logs-management</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/docker-container-security</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/product/oncall-management</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/customers</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/enterprise/overview</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/enterprise/demo</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/enterprise/resources</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/legal/terms</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/legal/privacy</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/legal/gdpr</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/legal/ccpa</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/legal</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://fyipe.com/compare/pagerduty</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/compare/pingdom</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/compare/statuspage.io</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/table/pagerduty</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/table/pingdom</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/table/statuspage.io</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/soc-2</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/soc-3</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/iso-27017</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/iso-27018</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/hipaa</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/pci</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>
https://fyipe.com/enterprise/download-resource/website-monitoring
</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>
https://fyipe.com/enterprise/download-resource/speed-equals-revenue
</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>
https://fyipe.com/enterprise/download-resource/best-practices
</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>
https://fyipe.com/enterprise/download-resource/planning-for-peak-performance
</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/sla</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/iso-27001</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/data-residency</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/dmca</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/subprocessors</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/legal/contact</loc>
<lastmod>2020-04-09T14:03:45+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://fyipe.com/files/soc-3.pdf</loc>
<lastmod>2020-01-21T16:41:54+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://fyipe.com/files/iso-27017.pdf</loc>
<lastmod>2020-01-21T16:41:54+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://fyipe.com/files/iso-27018.pdf</loc>
<lastmod>2020-01-21T16:41:54+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://fyipe.com/files/pci.pdf</loc>
<lastmod>2020-01-21T16:41:54+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://fyipe.com/files/iso-27001.pdf</loc>
<lastmod>2020-01-21T16:41:54+00:00</lastmod>
<priority>0.51</priority>
</url>
</urlset>

View File

@@ -177,14 +177,67 @@ app.get('/unsubscribe/:monitorId/:subscriberId', async function(req, res) {
}
try {
await axios({
method: 'PUT',
url: `${apiHost}/subscriber/unsubscribe/${monitorId}/${subscriberId}`,
const subscriptions = await axios({
method: 'GET',
url: `${apiHost}/subscriber/monitorList/${subscriberId}`,
});
if (subscriptions.data.data.length < 1) {
res.render('unsubscribe', {
message: 'You are currently not subscribed to any monitor',
});
} else {
res.render('subscriberMonitors', {
subscriptions: subscriptions.data.data,
defaultMonitor: monitorId,
});
}
} catch (err) {
res.render('unsubscribe', {
message: 'You have successfully unsubscribed from this monitor',
message:
'Encountered an error while trying to display your monitor list',
});
}
});
app.post('/unsubscribe', async function(req, res) {
let apiHost;
if (process.env.FYIPE_HOST) {
apiHost = 'https://' + process.env.FYIPE_HOST + '/api';
} else {
apiHost = 'http://localhost:3002/api';
}
try {
const { email, monitors } = req.body;
if (
!email ||
email[0] === null ||
email[0] === undefined ||
email[0] === ''
) {
throw Error;
} else if (
!monitors ||
monitors === null ||
monitors === undefined ||
monitors.length === 0
) {
res.render('unsubscribe', {
message: 'No monitor was selected',
});
} else {
monitors.forEach(async monitorId => {
await axios({
method: 'PUT',
url: `${apiHost}/subscriber/unsubscribe/${monitorId}/${email}`,
});
});
res.render('unsubscribe', {
message: 'You have been successfully unsubscribed.',
});
}
} catch (err) {
res.render('unsubscribe', {
message:
@@ -192,6 +245,7 @@ app.get('/unsubscribe/:monitorId/:subscriberId', async function(req, res) {
});
}
});
app.get('/product/docker-container-security', function(req, res) {
res.render('container-security', {
support: false,

View File

@@ -62,7 +62,7 @@
<div class="content">
<header>
<h1 style="line-height: unset;" class="Header-title common-PageTitle header-font header-size black">Make incident communication efficient. Build your Status Page now.</h1>
<h1 style="line-height: unset; font-size: 50px !important;" class="Header-title common-PageTitle header-font header-size black">Make incident communication efficient. Build your Status Page now.</h1>
<div style="margin-top: -100px">
<%- include("stars", {
description1: '"Best status page product on the internet!"',

View File

@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en" id="contact">
<head>
<meta charset="utf-8">
<title>Fyipe | Help and Support</title>
<meta name="description"
content="Fyipe monitors websites, API's, and servers and alerts your team if something goes wrong. It also keeps your customers updated about any downtime.">
<% include ./head %>
<link rel="stylesheet" href="/css/contact.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap">
<script src="/js/amplitude.js"></script>
<script type="module" async>
var IS_SAAS_SERVICE = !(window.location.href.indexOf('localhost') > -1 || window.location.href.indexOf('staging') > -1);
if (IS_SAAS_SERVICE) {
amplitude.getInstance().logEvent('PAGE VIEW: HOME > SUPPORT');
}
</script>
</head>
<body>
<div style=" display: flex;
justify-content: center;
flex-direction: column;
width: 100%;
align-items: center;
">
<div
style=" padding: 2px;background: #EEEEEE; border: 1px solid #CCCCCC;margin-top: 10px;text-align: center; width: 70%;">
<p style="padding: 8px; margin: 0;">
Select monitors you want to unsubscribe from:
</p>
<div style="padding: 2px; ;margin-top: 10px;text-align: center; width: 100%;padding-bottom: 40px;">
<form id="monitorForm" action="/unsubscribe" method="POST"
style="display:flex; flex-direction:column;align-items:center;justify-content: space-around;padding:10px">
<input name="email[]" value="<%=subscriptions[0].contactEmail%>" hidden>
<% for(var i=0; i < subscriptions.length; i++) { %>
<% if(subscriptions[i].monitorId==defaultMonitor){%>
<div style="font-size: 18px;margin-top: 10px;">
<input type="checkbox" name="monitors[]" value=<%=subscriptions[i].monitorId%> checked>
<label for="default">
<%= subscriptions[i].monitorName%>
</label>
</div>
<%}else{%>
<div style="font-size: 18px;margin-top: 10px;">
<input type="checkbox" name="monitors[]" value=<%=subscriptions[i].monitorId%>>
<label>
<%= subscriptions[i].monitorName%>
</label>
</div>
<%}%>
<%}%>
<input type="submit" value="Unsubscribe" style="margin-top: 80px;
width: 100px;
height: 40px;
font-size: 16px;
color: white;
border-radius: 5px;
background-color: black;
">
</form>
</div>
</div>
</div>
</body>
</html>

288
js-sdk/package-lock.json generated
View File

@@ -583,17 +583,6 @@
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
"dev": true,
"optional": true,
"dependencies": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
}
},
"node_modules/errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
@@ -676,17 +665,6 @@
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
"dev": true,
"optional": true,
"dependencies": {
"is-glob": "^3.1.0",
"path-dirname": "^1.0.0"
}
},
"node_modules/string.prototype.trimstart": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
@@ -1311,21 +1289,6 @@
"node": ">= 0.4"
}
},
"node_modules/watchpack-chokidar2/node_modules/readdirp": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
"dev": true,
"optional": true,
"dependencies": {
"graceful-fs": "^4.1.11",
"micromatch": "^3.1.10",
"readable-stream": "^2.0.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
@@ -3178,19 +3141,6 @@
"ret": "~0.1.10"
}
},
"node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
"dev": true,
"optional": true,
"dependencies": {
"remove-trailing-separator": "^1.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/schema-utils": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
@@ -4807,13 +4757,6 @@
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"node_modules/file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true,
"optional": true
},
"node_modules/@webassemblyjs/utf8": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz",
@@ -6255,13 +6198,6 @@
"resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz",
"integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg=="
},
"node_modules/nan": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
"dev": true,
"optional": true
},
"node_modules/@webassemblyjs/helper-fsm": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz",
@@ -6596,19 +6532,6 @@
"node": ">=6"
}
},
"node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
"dev": true,
"optional": true,
"dependencies": {
"is-extglob": "^2.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -6814,19 +6737,6 @@
"node": ">=4"
}
},
"node_modules/watchpack-chokidar2/node_modules/is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
"dev": true,
"optional": true,
"dependencies": {
"binary-extensions": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/des.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
@@ -7342,19 +7252,6 @@
"integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==",
"dev": true
},
"node_modules/watchpack-chokidar2": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz",
"integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==",
"dev": true,
"optional": true,
"dependencies": {
"chokidar": "^2.1.8"
},
"engines": {
"node": "<8.10.0"
}
},
"node_modules/webpack-cli/node_modules/supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
@@ -7386,24 +7283,6 @@
"node": ">=4"
}
},
"node_modules/watchpack-chokidar2/node_modules/fsevents": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"dependencies": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
},
"engines": {
"node": ">= 4.0"
}
},
"node_modules/posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -7413,16 +7292,6 @@
"node": ">=0.10.0"
}
},
"node_modules/bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true,
"optional": true,
"dependencies": {
"file-uri-to-path": "1.0.0"
}
},
"node_modules/caller-callsite": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
@@ -7760,27 +7629,6 @@
"integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
"dev": true
},
"node_modules/watchpack-chokidar2/node_modules/chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"dev": true,
"optional": true,
"dependencies": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.2.1",
"upath": "^1.1.1"
}
},
"node_modules/strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
@@ -10036,16 +9884,6 @@
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
"dev": true
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true,
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -11473,13 +11311,6 @@
"escape-string-regexp": "^1.0.5"
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true,
"optional": true
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -12944,13 +12775,6 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
},
"nan": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
"dev": true,
"optional": true
},
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -14958,118 +14782,6 @@
"watchpack-chokidar2": "^2.0.0"
}
},
"watchpack-chokidar2": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz",
"integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==",
"dev": true,
"optional": true,
"requires": {
"chokidar": "^2.1.8"
},
"dependencies": {
"anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
"dev": true,
"optional": true,
"requires": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
},
"dependencies": {
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
"dev": true,
"optional": true,
"requires": {
"remove-trailing-separator": "^1.0.1"
}
}
}
},
"chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"dev": true,
"optional": true,
"requires": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.2.1",
"upath": "^1.1.1"
}
},
"fsevents": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true,
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
},
"glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
"dev": true,
"optional": true,
"requires": {
"is-glob": "^3.1.0",
"path-dirname": "^1.0.0"
},
"dependencies": {
"is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
"dev": true,
"optional": true,
"requires": {
"is-extglob": "^2.1.0"
}
}
}
},
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
"dev": true,
"optional": true,
"requires": {
"binary-extensions": "^1.0.0"
}
},
"readdirp": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.11",
"micromatch": "^3.1.10",
"readable-stream": "^2.0.2"
}
}
}
},
"webpack": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz",

View File

@@ -6,6 +6,8 @@
saas:
isSaasService: true
isMongoPrimaryBackupServiceEnabled: true
isMongoSecondaryBackupServiceEnabled: true
slackErrorLog:
webhook: https://hooks.slack.com/services/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
channel: fyipe-logs

View File

@@ -28,7 +28,8 @@
"scripts": {
"delete-all-local-branches": "git branch | grep -v 'master' | xargs git branch -D",
"lint": "eslint '**/*.js' -c .eslintrc.json --ignore-path .eslintignore",
"fix-lint": "eslint '**/*.js' -c .eslintrc.json --ignore-path .eslintignore --fix"
"fix-lint": "eslint '**/*.js' -c .eslintrc.json --ignore-path .eslintignore --fix",
"staging-test": "cd smoke-test && npm run-script staging-test"
},
"repository": {
"type": "git",

17
smoke-test/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,17 @@
{
// PLEASE DO NOT REMOVE THIS CONFIGURATION FILE FROM GIT REPO
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"command": "npm run-script debug-staging-test",
"name": "Debug Smoke Tests",
"request": "launch",
"type": "node-terminal"
}
]
}

View File

@@ -1,91 +1,57 @@
const puppeteer = require('puppeteer');
const utils = require('./test-utils');
const init = require('./test-init');
const { Cluster } = require('puppeteer-cluster');
require('should');
let browser, page;
// user credentials
const email = utils.generateRandomBusinessEmail();
const password = '1234567890';
const user = {
email,
password,
};
describe('Enterprise Accounts API', () => {
const operationTimeOut = 100000;
beforeAll(async done => {
jest.setTimeout(200000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
await init.registerEnterpriseUser(user, page);
const cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_PAGE,
puppeteerOptions: utils.puppeteerLaunchConfig,
puppeteer,
timeout: 120000,
});
cluster.on('taskerror', err => {
throw err;
});
// Register user
await cluster.task(async ({ page, data }) => {
const user = {
email: data.email,
password: data.password,
};
// user
await init.registerEnterpriseUser(user, page);
});
await cluster.queue({ email, password });
await cluster.idle();
await cluster.close();
done();
});
afterAll(async done => {
browser.close();
done();
});
it(
'Should login valid user',
async done => {
const cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_PAGE,
puppeteerOptions: utils.puppeteerLaunchConfig,
puppeteer,
timeout: 100000,
await init.logout(page);
await init.loginUser(user, page);
const localStorageData = await page.evaluate(() => {
const json = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
json[key] = localStorage.getItem(key);
}
return json;
});
cluster.on('taskerror', err => {
throw err;
});
await cluster.task(async ({ page, data }) => {
const user = {
email: data.email,
password: data.password,
};
await init.loginUser(user, page);
const localStorageData = await page.evaluate(() => {
const json = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
json[key] = localStorage.getItem(key);
}
return json;
});
localStorageData.should.have.property('access_token');
localStorageData.should.have.property('email', email);
page.url().should.containEql(utils.DASHBOARD_URL);
});
cluster.queue({ email, password });
await cluster.idle();
await cluster.close();
localStorageData.should.have.property('access_token');
localStorageData.should.have.property('email', email);
page.url().should.containEql(utils.DASHBOARD_URL);
done();
},
operationTimeOut

View File

@@ -1,10 +1,9 @@
const puppeteer = require('puppeteer');
const utils = require('./test-utils');
const init = require('./test-init');
const { Cluster } = require('puppeteer-cluster');
require('should');
let browser, page;
// user credentials
const user = {
email: utils.generateRandomBusinessEmail(),
@@ -13,162 +12,145 @@ const user = {
describe('Enterprise Dashboard API', () => {
const operationTimeOut = 100000;
let cluster;
const monitorName = utils.generateRandomString();
const componentName = utils.generateRandomString();
beforeAll(async () => {
beforeAll(async done => {
jest.setTimeout(200000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
await init.registerEnterpriseUser(user, page);
await init.logout(page);
await init.loginUser(user, page);
cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_PAGE,
puppeteerOptions: utils.puppeteerLaunchConfig,
puppeteer,
timeout: 120000,
});
cluster.on('taskerror', err => {
throw err;
});
// Register user
return await cluster.execute(null, async ({ page }) => {
// user
await init.registerEnterpriseUser(user, page);
await init.logout(page);
await init.loginUser(user, page);
});
done();
});
afterAll(async done => {
await cluster.execute(null, async ({ page }) => {
// delete monitor
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#more-details-${monitorName}`);
await page.click(`#more-details-${monitorName}`);
await page.waitForSelector(`#delete_${monitorName}`);
await page.click(`#delete_${monitorName}`);
await page.waitForSelector('#deleteMonitor');
await page.click('#deleteMonitor');
await page.waitForSelector('#deleteMonitor', { hidden: true });
// delete component
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#componentSettings`);
await page.click(`#componentSettings`);
await page.waitForSelector(`#advanced`);
await page.click(`#advanced`);
await page.waitForSelector(`#delete-component-${componentName}`);
await page.click(`#delete-component-${componentName}`);
await page.waitForSelector('#deleteComponent');
await page.click('#deleteComponent');
await page.waitForSelector('#deleteComponent', { hidden: true });
// delete monitor
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await cluster.idle();
await cluster.close();
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#more-details-${monitorName}`);
await page.click(`#more-details-${monitorName}`);
await page.waitForSelector(`#delete_${monitorName}`);
await page.click(`#delete_${monitorName}`);
await page.waitForSelector('#deleteMonitor');
await page.click('#deleteMonitor');
await page.waitForSelector('#deleteMonitor', { hidden: true });
// delete component
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#componentSettings`);
await page.click(`#componentSettings`);
await page.waitForSelector(`#advanced`);
await page.click(`#advanced`);
await page.waitForSelector(`#delete-component-${componentName}`);
await page.click(`#delete-component-${componentName}`);
await page.waitForSelector('#deleteComponent');
await page.click('#deleteComponent');
await page.waitForSelector('#deleteComponent', { hidden: true });
await browser.close();
done();
});
it(
'Should create new monitor with correct details',
async () => {
return await cluster.execute(null, async ({ page }) => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle0',
});
await page.$eval('#components', el => el.click());
// Fill and submit New Component form
await page.waitForSelector('#form-new-component');
await page.click('input[id=name]');
await page.type('input[id=name]', componentName);
await page.click('button[type=submit]');
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle0',
});
await page.$eval('#components', el => el.click());
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForTimeout(3000);
await page.$('#form-new-monitor', {
visible: true,
});
// Fill and submit New Monitor form
await page.click('input[id=name]', { visible: true });
await page.type('input[id=name]', monitorName);
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.click('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
await page.waitForTimeout(3000);
let spanElement;
spanElement = await page.$(`#monitor-title-${monitorName}`);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(monitorName);
async done => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle0',
});
await page.$eval('#components', el => el.click());
// Fill and submit New Component form
await page.waitForSelector('#form-new-component');
await page.click('input[id=name]');
await page.type('input[id=name]', componentName);
await page.click('button[type=submit]');
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle0',
});
await page.$eval('#components', el => el.click());
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector('#form-new-monitor', {
visible: true,
});
// Fill and submit New Monitor form
await page.click('input[id=name]', { visible: true });
await page.type('input[id=name]', monitorName);
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.click('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
let spanElement;
spanElement = await page.waitForSelector(
`#monitor-title-${monitorName}`
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(monitorName);
done();
},
operationTimeOut
);
it(
'Should not create new monitor when details are incorrect',
async () => {
return await cluster.execute(null, async ({ page }) => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle0',
});
await page.$eval('#components', el => el.click());
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForTimeout(3000);
await page.$('#form-new-monitor', {
visible: true,
});
// Submit New Monitor form with incorrect details
await page.waitForSelector('#name');
await page.click('[data-testId=type_url]');
await page.waitForTimeout(3000);
await page.$('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
await page.waitForTimeout(3000);
let spanElement;
spanElement = await page.$(
'#form-new-monitor span#field-error'
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(
'This field cannot be left blank'
);
async done => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle0',
});
await page.$eval('#components', el => el.click());
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector('#form-new-monitor', {
visible: true,
});
// Submit New Monitor form with incorrect details
await page.waitForSelector('#name');
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
let spanElement;
spanElement = await page.waitForSelector(
'#form-new-monitor span#field-error'
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly('This field cannot be left blank');
done();
},
operationTimeOut
);

View File

@@ -15,95 +15,94 @@ describe('Monitor API', () => {
const componentName = utils.generateRandomString();
const monitorName = utils.generateRandomString();
let cluster;
beforeAll(async (done) => {
beforeAll(async done => {
jest.setTimeout(500000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
await init.registerUser(user,page);
await init.registerUser(user, page);
done();
});
afterAll(async done => {
// delete monitor
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#more-details-${monitorName}`);
await page.click(`#more-details-${monitorName}`);
await page.waitForSelector(`#delete_${monitorName}`);
await page.click(`#delete_${monitorName}`);
await page.waitForSelector('#deleteMonitor');
await page.click('#deleteMonitor');
afterAll(async done => {
// delete monitor
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#more-details-${monitorName}`);
await page.click(`#more-details-${monitorName}`);
await page.waitForSelector(`#delete_${monitorName}`);
await page.click(`#delete_${monitorName}`);
await page.waitForSelector('#deleteMonitor');
await page.click('#deleteMonitor');
await page.waitForSelector('.ball-beat', { visible: true });
await page.waitForSelector('.ball-beat', { hidden: true });
await page.waitForSelector('.ball-beat', { visible: true });
await page.waitForSelector('.ball-beat', { hidden: true });
// delete component
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
// delete component
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#componentSettings`);
await page.click(`#componentSettings`);
await page.waitForSelector(`#advanced`);
await page.click(`#advanced`);
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector(`#componentSettings`);
await page.click(`#componentSettings`);
await page.waitForSelector(`#advanced`);
await page.click(`#advanced`);
await page.waitForSelector(`#delete-component-${componentName}`);
await page.click(`#delete-component-${componentName}`);
await page.waitForSelector('#deleteComponent');
await page.click('#deleteComponent');
await page.waitForSelector('#deleteComponent', { hidden: true });
await page.waitForSelector(`#delete-component-${componentName}`);
await page.click(`#delete-component-${componentName}`);
await page.waitForSelector('#deleteComponent');
await page.click('#deleteComponent');
await page.waitForSelector('#deleteComponent', { hidden: true });
await browser.close();
done();
});
it(
'Should create new component',
async (done) => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
async done => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
// Fill and submit New Component form
await page.waitForSelector('#form-new-component');
await page.click('input[id=name]');
await page.type('input[id=name]', componentName);
await page.click('#addComponentButton');
// Fill and submit New Component form
await page.waitForSelector('#form-new-component');
await page.click('input[id=name]');
await page.type('input[id=name]', componentName);
await page.click('#addComponentButton');
await page.waitForSelector('#monitors', { visible: true });
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#monitors', { visible: true });
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components', { visible: true });
await page.click('#components');
await page.waitForSelector('#components', { visible: true });
await page.click('#components');
let spanElement;
spanElement = await page.waitForSelector(
`span#component-title-${componentName}`
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(componentName);
let spanElement;
spanElement = await page.waitForSelector(
`span#component-title-${componentName}`
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(componentName);
done();
},
operationTimeOut
@@ -111,81 +110,80 @@ describe('Monitor API', () => {
it(
'Should create new monitor with correct details',
async (done) => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
async done => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector('#form-new-monitor', {
visible: true,
});
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector('#form-new-monitor', {
visible: true,
});
// Fill and submit New Monitor form
await page.click('input[id=name]', { visible: true });
await page.type('input[id=name]', monitorName);
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.click('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
// Fill and submit New Monitor form
await page.click('input[id=name]', { visible: true });
await page.type('input[id=name]', monitorName);
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.click('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
let spanElement;
spanElement = await page.waitForSelector(
`#monitor-title-${monitorName}`,
{ visible: true }
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(monitorName);
let spanElement;
spanElement = await page.waitForSelector(
`#monitor-title-${monitorName}`,
{ visible: true }
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly(monitorName);
done();
done();
},
operationTimeOut
);
it(
'Should not create new monitor when details that are incorrect',
async (done) => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
async done => {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'domcontentloaded',
});
await page.waitForSelector('#components');
await page.click('#components');
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector('#form-new-monitor', {
visible: true,
});
// Submit New Monitor form with incorrect details
await page.click('input[id=name]', { visible: true });
await page.type('input[id=name]', '');
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.click('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
// Navigate to details page of component created in previous test
await page.waitForSelector(`#more-details-${componentName}`);
await page.click(`#more-details-${componentName}`);
await page.waitForSelector('#form-new-monitor', {
visible: true,
});
// Submit New Monitor form with incorrect details
await page.click('input[id=name]', { visible: true });
await page.type('input[id=name]', '');
await page.click('[data-testId=type_url]');
await page.waitForSelector('#url');
await page.click('#url');
await page.type('#url', 'https://google.com');
await page.click('button[type=submit]');
let spanElement;
spanElement = await page.waitForSelector(
'#form-new-monitor span#field-error',
{ visible: true }
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly( 'This field cannot be left blank');
let spanElement;
spanElement = await page.waitForSelector(
'#form-new-monitor span#field-error',
{ visible: true }
);
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
spanElement.should.be.exactly('This field cannot be left blank');
done();
done();
},
operationTimeOut
);
});

View File

@@ -5,8 +5,9 @@
"main": "index.test.js",
"scripts": {
"test": "jest --forceExit --runInBand ./*.test.js",
"enterprise-test": "jest --forceExit --runInBand ./*.test.enterprise.js",
"staging-test": "export HEADLESS=false && export HOME_URL=https://staging.fyipe.com && export ACCOUNTS_URL=https://staging.fyipe.com/accounts && export ADMIN_DASHBOARD_URL=https://staging.fyipe.com/admin && export DASHBOARD_URL=https://staging.fyipe.com/dashboard && export BACKEND_URL=https://staging.fyipe.com/api && export STATUSPAGE_URL=https://staging.fyipe.com/status-page && export APIDOCS_URL=https://staging.fyipe.com/docs && jest --forceExit --runInBand ./*.test.js"
"enterprise-test": "jest --forceExit --runInBand ./*enterprise.js",
"staging-test": "export HOME_URL=https://staging.fyipe.com && export ACCOUNTS_URL=https://staging.fyipe.com/accounts && export ADMIN_DASHBOARD_URL=https://staging.fyipe.com/admin && export DASHBOARD_URL=https://staging.fyipe.com/dashboard && export BACKEND_URL=https://staging.fyipe.com/api && export STATUSPAGE_URL=https://staging.fyipe.com/status-page && export APIDOCS_URL=https://staging.fyipe.com/docs && jest --forceExit --runInBand ./*.test.js",
"debug-staging-test": "export SLOMO=20 && export HEADLESS=false && npm run-script staging-test"
},
"keywords": [],
"author": "",

View File

@@ -170,9 +170,13 @@ describe('Check scheduled maintenace', () => {
{ hidden: true }
);
await page.click('input[name=endDate]');
await page.click('div.MuiPickersCalendar-week:nth-child(5) > div:nth-child(6)'); // To select the last week and last day of the month.
await page.click(
'div.MuiPickersCalendar-week:nth-child(5) > div:nth-child(6)'
); // To select the last week and last day of the month.
await page.click('span.MuiTypography-body1:nth-child(14)'); // This selects '11'
await page.click('span.MuiPickersClockNumber-clockNumber:nth-child(15)'); // This selects '55'. 11:55 is the highest possible value from the clock library html elements
await page.click(
'span.MuiPickersClockNumber-clockNumber:nth-child(15)'
); // This selects '55'. 11:55 is the highest possible value from the clock library html elements
await page.click('div.MuiDialogActions-root button:nth-child(2)');
await page.waitForSelector(
'div.MuiDialogActions-root button:nth-child(2)',

View File

@@ -86,14 +86,16 @@ describe('Check status-page up', () => {
await page.$eval('#components', el => el.click());
// Fill and submit New Component form
await page.waitForSelector('#form-new-component');
await page.waitForSelector('#form-new-component', { visible: true });
await page.waitForSelector('input[id=name]', { visible: true });
await page.click('input[id=name]');
await page.type('input[id=name]', componentName);
await page.click('button[type=submit]');
// Create a Manual Monitor
await page.waitForSelector('#form-new-monitor', { visible: true });
await page.click('input[id=name]', { visible: true });
await page.waitForSelector('input[id=name]', { visible: true });
await page.click('input[id=name]');
await page.type('input[id=name]', monitorName);
await page.click('[data-testId=type_manual]');
await page.waitForSelector('#description');
@@ -101,7 +103,7 @@ describe('Check status-page up', () => {
await page.type('#description', 'My Manual Monitor');
await page.click('button[type=submit]');
// To confirm the manual monitor is created
// To confirm the manual monitor is created.
let spanElement = await page.waitForSelector(
`#monitor-title-${monitorName}`
);
@@ -196,14 +198,19 @@ describe('Check status-page up', () => {
await page.click(`#monitorCreateIncident_${monitorName}`);
await page.waitForSelector('#incidentTitleLabel');
await page.click('#createIncident');
await page.waitForSelector('#viewIncident-0');
await page.click('#closeIncident_0');
await page.waitForSelector('#closeIncident_0', { hidden: true });
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#viewIncident-0');
await page.click('#closeIncident_0');
await page.waitForSelector('#closeIncident_0', { hidden: true });
await init.navigateToStatusPage(page);
await page.reload({
waitUntil: 'networkidle0',
});
let spanElement = await page.waitForSelector('#status-note');
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
@@ -246,14 +253,19 @@ describe('Check status-page up', () => {
await page.waitForSelector('#incidentTitleLabel');
await init.selectByText('#incidentType', 'Degraded', page);
await page.click('#createIncident');
await page.waitForSelector('#viewIncident-0');
await page.click('#closeIncident_0');
await page.waitForSelector('#closeIncident_0', { hidden: true });
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#viewIncident-0');
await page.click('#closeIncident_0');
await page.waitForSelector('#closeIncident_0', { hidden: true });
await init.navigateToStatusPage(page);
await page.reload({
waitUntil: 'networkidle0',
});
let spanElement = await page.waitForSelector('#status-note');
spanElement = await spanElement.getProperty('innerText');
spanElement = await spanElement.jsonValue();
@@ -300,13 +312,15 @@ describe('Check status-page up', () => {
await page.keyboard.up('Control');
await page.type('#description', note);
await page.click('#createIncident');
await page.waitForSelector('#viewIncident-0');
await page.click('#closeIncident_0');
await page.waitForSelector('#closeIncident_0', { hidden: true });
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#viewIncident-0');
await page.click('#closeIncident_0');
await page.waitForSelector('#closeIncident_0', { hidden: true });
await init.navigateToStatusPage(page);
await page.reload({
waitUntil: 'networkidle0',

View File

@@ -11,7 +11,8 @@ module.exports = {
* @description Registers a new user.
* @returns { void }
*/
registerUser: async function(user, page) {
registerUser: async function (user, page) {
if (
utils.BACKEND_URL.includes('localhost') ||
utils.BACKEND_URL.includes('staging.fyipe.com')
@@ -35,10 +36,10 @@ module.exports = {
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', '1234567890');
await Promise.all([
page.waitForSelector(`form#card-form`),
page.click('button[type=submit]'),
]);
await page.click('button[type=submit]')
await page.waitForSelector(`form#card-form`, {
visible: true,
})
await page.waitForSelector('.__PrivateStripeElement > iframe', {
visible: true,
@@ -82,37 +83,26 @@ module.exports = {
await page.type('input[name=zipCode]', utils.user.address.zipcode);
await page.select('#country', 'India');
await page.click('button[type=submit]');
try {
const signupResponse = await page.waitForResponse(
response =>
response.url().includes('/user/signup') &&
response.status() === 200
);
if (signupResponse) {
const signupData = await signupResponse.text();
const parsedSignupData = JSON.parse(signupData);
if (parsedSignupData.verificationToken) {
await request
.get(
`/user/confirmation/${parsedSignupData.verificationToken}`
)
.redirects(0);
}
}
} catch (error) {
//catch
const signupResponse = await page.waitForResponse(
response =>
response.url().includes('/user/signup') &&
response.status() === 200
);
if (signupResponse._status !== 200) {
throw new Error("Sign up did not return 200")
}
}
},
loginUser: async function(user, page) {
loginUser: async function (user, page) {
const { email, password } =
utils.BACKEND_URL.includes('localhost') ||
utils.BACKEND_URL.includes('staging')
utils.BACKEND_URL.includes('staging')
? user
: {
email: 'user@fyipe.com',
password: 'mVzkm{LAP)mNC8t23ehqifb2p',
};
email: 'user@fyipe.com',
password: 'mVzkm{LAP)mNC8t23ehqifb2p',
};
await page.goto(utils.ACCOUNTS_URL + '/login', {
waitUntil: 'networkidle2',
});
@@ -125,7 +115,7 @@ module.exports = {
await page.waitForSelector('#home', { visible: true, timeout: 100000 });
},
loginEnterpriseUser: async function(user, page) {
loginEnterpriseUser: async function (user, page) {
const { email, password } = user;
await page.goto(utils.ACCOUNTS_URL + '/login', {
waitUntil: 'networkidle2',
@@ -142,7 +132,7 @@ module.exports = {
timeout: 100000,
});
},
registerEnterpriseUser: async function(user, page) {
registerEnterpriseUser: async function (user, page) {
const masterAdmin = {
email: 'masteradmin@hackerbay.io',
password: '1234567890',
@@ -217,7 +207,7 @@ module.exports = {
//catch
}
},
logout: async function(page) {
logout: async function (page) {
await page.goto(utils.ADMIN_DASHBOARD_URL);
await page.waitForSelector('button#profile-menu', { visible: true });
await page.click('button#profile-menu');
@@ -226,7 +216,7 @@ module.exports = {
await page.reload();
await page.waitForTimeout(3000);
},
saasLogout: async function(page) {
saasLogout: async function (page) {
await page.goto(utils.DASHBOARD_URL);
await page.waitForSelector('button#profile-menu', { visible: true });
await page.click('button#profile-menu');
@@ -234,7 +224,7 @@ module.exports = {
await page.click('button#logout-button');
await page.reload({ waitUntil: 'networkidle0' });
},
selectByText: async function(selector, text, page) {
selectByText: async function (selector, text, page) {
await page.click(selector, { delay: 100 });
await page.keyboard.type(text);
const noOption = await page.$('div.css-1gl4k7y');
@@ -242,12 +232,12 @@ module.exports = {
await page.keyboard.type(String.fromCharCode(13));
}
},
clear: async function(selector, page) {
clear: async function (selector, page) {
const input = await page.$(selector);
await input.click({ clickCount: 3 });
await input.type('');
},
renameProject: async function(newProjectName, page) {
renameProject: async function (newProjectName, page) {
await page.waitForSelector('#projectSettings');
await page.click('#projectSettings');
await page.waitForSelector('input[name=project_name]');
@@ -255,7 +245,7 @@ module.exports = {
await page.type('input[name=project_name]', newProjectName);
await page.click('#btnCreateProject');
},
navigateToComponentDetails: async function(component, page) {
navigateToComponentDetails: async function (component, page) {
// Navigate to Components page
await page.goto(utils.DASHBOARD_URL, { waitUntil: 'networkidle0' });
await page.waitForSelector('#components', { visible: true });
@@ -265,7 +255,7 @@ module.exports = {
await page.waitForSelector(`#more-details-${component}`);
await page.$eval(`#more-details-${component}`, e => e.click());
},
addMonitorToStatusPage: async function(componentName, monitorName, page) {
addMonitorToStatusPage: async function (componentName, monitorName, page) {
await page.goto(utils.DASHBOARD_URL, {
waitUntil: 'networkidle2',
});
@@ -290,7 +280,7 @@ module.exports = {
await page.click('ul > li:last-of-type #manual-monitor-checkbox');
await page.click('#btnAddStatusPageMonitors');
},
navigateToStatusPage: async function(page) {
navigateToStatusPage: async function (page) {
await page.waitForSelector('#statusPages');
await page.click('#statusPages');
await page.waitForSelector('#statusPagesListContainer');
@@ -303,14 +293,14 @@ module.exports = {
link = await link.jsonValue();
await page.goto(link);
},
navigateToMonitorDetails: async function(monitorName, page) {
navigateToMonitorDetails: async function (monitorName, page) {
await page.waitForSelector('#components');
await page.click('#components');
await page.waitForSelector(`#view-resource-${monitorName}`);
await page.click(`#view-resource-${monitorName}`);
await page.waitForSelector(`#monitor-title-${monitorName}`);
},
growthPlanUpgrade: async function(page) {
growthPlanUpgrade: async function (page) {
await page.goto(utils.DASHBOARD_URL);
await page.waitForSelector('#projectSettings', { visible: true });
await page.click('#projectSettings');

View File

@@ -1,3 +1,4 @@
const { internet } = require('faker');
const faker = require('faker');
const user = faker.helpers.createCard();
@@ -10,19 +11,21 @@ user.message = 'Test message';
const puppeteerLaunchConfig = {
headless: process.env.HEADLESS === 'false' ? false : true,
defaultViewport: null,
slowMo: process.env.SLOMO ? parseInt(process.env.SLOMO) : null,
args: [
'--start-maximized',
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
'--proxy-server=',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920x1080',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
],
};

View File

@@ -18,15 +18,16 @@ if (!NODE_ENV || NODE_ENV === 'development') {
require('dotenv').config();
}
let apiHost = 'http://localhost:3002/api';
if (process.env.BACKEND_URL) {
apiHost = 'http://' + process.env.BACKEND_URL + '/api';
}
app.get(['/env.js', '/status-page/env.js'], function(req, res) {
let REACT_APP_FYIPE_HOST = null;
let REACT_APP_BACKEND_PROTOCOL = null;
if (!process.env.FYIPE_HOST) {
if (req.host.includes('localhost')) {
REACT_APP_FYIPE_HOST = 'http://' + req.host;
} else {
REACT_APP_FYIPE_HOST = 'https://' + req.host;
}
REACT_APP_FYIPE_HOST = req.hostname;
} else {
REACT_APP_FYIPE_HOST = process.env.FYIPE_HOST;
if (REACT_APP_FYIPE_HOST.includes('*.')) {
@@ -51,19 +52,12 @@ app.get(['/env.js', '/status-page/env.js'], function(req, res) {
app.use('/.well-known/acme-challenge/:token', async function(req, res) {
// make api call to backend and fetch keyAuthorization
const { token } = req.params;
let apiHost;
if (process.env.FYIPE_HOST) {
apiHost = 'https://' + process.env.FYIPE_HOST + '/api';
} else {
apiHost = 'http://localhost:3002/api';
}
const url = `${apiHost}/ssl/challenge/authorization/${token}`;
const response = await axios.get(url);
res.send(response.data);
});
app.use(async function(req, res, next) {
let apiHost;
app.use('/', async function(req, res, next) {
const host = req.hostname;
if (
host &&
@@ -73,11 +67,6 @@ app.use(async function(req, res, next) {
) {
return next();
}
if (process.env.BACKEND_URL) {
apiHost = 'http://' + process.env.BACKEND_URL + '/api';
} else {
apiHost = 'http://localhost:3002/api';
}
const response = await fetch(
`${apiHost}/statusPage/tlsCredential?domain=${host}`
@@ -207,13 +196,6 @@ function createDir(dirPath) {
path.resolve(process.cwd(), 'src', 'credentials', 'private.key')
),
SNICallback: async function(domain, cb) {
let apiHost;
if (process.env.FYIPE_HOST) {
apiHost = 'https://' + process.env.FYIPE_HOST + '/api';
} else {
apiHost = 'http://localhost:3002/api';
}
const res = await fetch(
`${apiHost}/statusPage/tlsCredential?domain=${domain}`
).then(res => res.json());

View File

@@ -31,9 +31,10 @@ if (
dashboardUrl = protocol + '//localhost:3000/dashboard';
accountsUrl = protocol + '//localhost:3003/accounts';
} else if (env('FYIPE_HOST')) {
apiUrl = protocol + `//${env('FYIPE_HOST')}/api`;
dashboardUrl = protocol + `//${env('FYIPE_HOST')}/dashboard`;
accountsUrl = protocol + `//${env('FYIPE_HOST')}/accounts`;
const FYIPE_HOST = env('FYIPE_HOST').replace(/(http:\/\/|https:\/\/)/, ''); // remove any protocol that might have been added
apiUrl = protocol + `//${FYIPE_HOST}/api`;
dashboardUrl = protocol + `//${FYIPE_HOST}/dashboard`;
accountsUrl = protocol + `//${FYIPE_HOST}/accounts`;
}
export const API_URL = apiUrl;