Skip to content

Commit

Permalink
Merge pull request #38 from Ktraveller285/dev-station
Browse files Browse the repository at this point in the history
Dev station
  • Loading branch information
Ktraveller285 authored Sep 29, 2024
2 parents 828f077 + 8ed06a9 commit b721a1b
Show file tree
Hide file tree
Showing 13 changed files with 125 additions and 233 deletions.
190 changes: 1 addition & 189 deletions server/cron.ts
Original file line number Diff line number Diff line change
@@ -1,191 +1,3 @@
import fetch from 'node-fetch';
import { createTransport } from 'nodemailer';
// .envファイルを読み込む(データベースの接続情報等が記載されている)
import * as dotenv from 'dotenv';
dotenv.config({ path: `${__dirname}/.env` });
import { Train } from './src/interfaces/train.interface';

import { DataSource, Repository } from 'typeorm';
import { Notice } from './src/entities/notice.entity';

export class Cron {
static async execute(NoticeRepository: Repository<Notice>) {
// メールを送信するためのインスタンスを初期化
let mailTransporter = await Cron.getMailTransporter();

// 検索する日付を取得
let findDate = new Date();
if (0 <= findDate.getHours() && findDate.getHours() <= 1) {
// 深夜 00:00〜01:59ならば、前日扱いとする
findDate.setDate(findDate.getDate() - 1);
}
let findDateString = Cron.getDateString(findDate);

// 今日の日付の通知登録を取得
let notices = await NoticeRepository.find({
where: {
noticeDate: findDateString,
notified: false,
},
});

// 通知登録配列を反復
for (let notice of notices) {
// 当該通知登録の路線の在線情報を取得
let trains = await Cron.getTrains(notice.lineName);
// 当該通知登録の列車番号を検索
let targetTrain = undefined;
for (let train of trains) {
if (train.no == notice.trainNumber) {
targetTrain = train;
}
}

// 設定された運休判断時刻の取得
let today = new Date();
let cancelDecisionDate = notice.cancelDecisionTime
? new Date(
`${Cron.getDateString(today)} ${notice.cancelDecisionTime}:00`
)
: null;

let isSuspended = false;
let isDeley = false;

if (
targetTrain == undefined &&
cancelDecisionDate &&
cancelDecisionDate.getTime() < Date.now()
) {
// 列車番号が見つからず、運休判断時刻が登録されており、運休判断時刻が過ぎていれば運休とする
isSuspended = true;
} else if (targetTrain && targetTrain.delayMinutes >= 15) {
// また列車番号が見つかり、15分以上の遅延になっていたら遅延とする
isDeley = true;
}

// 運休 or 遅延ならばメールを送信し、通知済みフラグをtrueにする
if (isSuspended || isDeley) {
await this.sendNoticeEmail(notice, isSuspended, isDeley, targetTrain);
}
}

// スリープ防止
await fetch('https://jr-trainformation.onrender.com/');
}

/**
* メールの送信
* @param notice 通知の登録状況
* @param isSuspended 列車が運休になっているかのフラグ
* @param isDeley 列車が遅延しているかのフラグ
* @param train 取得した列車情報
*/
static async sendNoticeEmail(
notice: Notice,
isSuspended: boolean,
isDeley: boolean,
train?: Train
) {
let sendResult;
let mailTransporter = Cron.getMailTransporter();

// メールの送信日時の取得
const sentDateString = Cron.getDateTimeString(new Date());

// 送信するメールの定義
let detailText = '';
if (train) {
detailText = `種別:${train.displayType}
列車名:${train.nickname}
行先:${train.dest}
遅れ:${train.delayMinutes}分`;
}
let mail = {
from: process.env['EMAIL_FROM'],
to: notice.noticeEmail,
subject: `${notice.trainNumber} 運行情報`,
text: `darinono.info 運行情報通知サービスです。
登録されている以下の列車が${isDeley ? '遅延' : '運休'}している可能性があります。
列車番号:${notice.trainNumber}
${detailText}
${sentDateString}時点の情報です
※最新の情報は https://jr-trainformation.herokuapp.com/ にてご確認ください
※遅延証明書は https://delay.trafficinfo.westjr.co.jp/ からご利用ください
ご利用ありがとうございます。`,
};

// メールの送信処理
try {
sendResult = await mailTransporter.sendMail(mail);
console.log(`メールを送信しました ${notice.noticeEmail}`, notice);
} catch (e: any) {
console.error('メールが送信できませんでした', e);
return;
}
if (sendResult?.rejected && sendResult.rejected.length >= 1) {
console.error('メールが拒否されました', sendResult?.rejected);
}

// 送信済みとしてマークする
notice.notified = true;
await notice.save();
}

/**
* 日時文字列の取得
* @param date Date オブジェクト
* @return 日時文字列 (例: '2022/01/01 00:00')
*/
static getDateTimeString(date: Date) {
const hourString = new String(date.getHours()).padStart(2, '0');
const minuteString = new String(date.getMinutes()).padStart(2, '0');
return `${Cron.getDateString(date)} ${hourString}:${minuteString}`;
}

/**
* 日付文字列の取得
* @param date Date オブジェクト
* @return 日付文字列 (例: '2022/01/01')
*/
static getDateString(date: Date) {
return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
}

/**
* メール送信に必要な列車情報の取得
* @param lineName 路線名
* @returns 列車情報の配列
*/
static async getTrains(lineName: string): Promise<any[]> {
const response = await fetch(
`https://www.train-guide.westjr.co.jp/api/v3/${lineName}.json`
);
const object = await response.json();
return object.trains;
}

/**
* nodemailerのインスタンス生成
* @returns メールを送信するためのインスタンス
*/
static getMailTransporter() {
return createTransport({
host: process.env['EMAIL_SMTP_HOST'],
port: parseInt(process.env['EMAIL_SMTP_PORT'] || '587', 10),
auth: {
user: process.env['EMAIL_SMTP_USERNAME'],
pass: process.env['EMAIL_SMTP_PW'],
},
});
}
static async execute() {}
}

/*
(async () => {
await Cron.execute();
})();
*/
7 changes: 2 additions & 5 deletions server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import * as express from 'express';
const app = express();
app.use(express.json());

// データベース接続を初期化
import { AppDataSource, NoticeRepository } from './src/database';

// Angularアプリケーションを静的ファイルとしてServe
app.use(express.static(path.join(__dirname, '../dist/jr-trainformation/')));

Expand All @@ -31,7 +28,7 @@ app.get('*', (req, res) => {
// 非同期処理を実行
(async () => {
// データベースの接続完了まで待機
await AppDataSource.initialize();
// await AppDataSource.initialize();

// サーバを開始
const server = app.listen(process.env['PORT'] || 8080, () => {
Expand All @@ -47,6 +44,6 @@ var node_cron = require('node-cron');
node_cron.schedule('* */10 * * *', () => {
//console.log('running a task every 10 minutes');
(async () => {
await Cron.execute(NoticeRepository);
await Cron.execute();
})();
});
23 changes: 0 additions & 23 deletions server/src/database.ts

This file was deleted.

15 changes: 1 addition & 14 deletions server/src/entities/notice.entity.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm';

@Entity()
export class Notice extends BaseEntity {
@PrimaryGeneratedColumn()
export interface NotifyEntity {
id: number;

@Column()
noticeEmail: string;

@Column()
lineName: string;

@Column()
trainNumber: string;

@Column()
noticeDate: string;

@Column()
cancelDecisionTime: string;

@Column({
default: false,
})
notified: boolean;

@Column()
ipAddress: string;
}
4 changes: 2 additions & 2 deletions server/src/routes/notice.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Router } from 'express';
// データベース接続を初期化
import { AppDataSource, NoticeRepository } from '../database';

const noticeRouter = Router();

Expand All @@ -9,6 +8,7 @@ const noticeRouter = Router();
* 通知を登録するためのAPIですけど…
*/
noticeRouter.post('/register', async (req, res) => {
/*
try {
let item = await NoticeRepository.save({
noticeEmail: req.body.noticeEmail || null,
Expand All @@ -23,7 +23,7 @@ noticeRouter.post('/register', async (req, res) => {
console.log(item);
} catch (e: any) {
res.status(400).send(e.toString());
}
}*/
});

export default noticeRouter;
5 changes: 5 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router';
import { LineDetailComponent } from './line-detail/line-detail.component';
import { LineSelectComponent } from './line-select/line-select.component';
import { NoticeRegisterComponent } from './notice-register/notice-register.component';
import { StationListComponent } from './station-list/station-list.component';

const routes: Routes = [
{
Expand All @@ -17,6 +18,10 @@ const routes: Routes = [
path: 'notice',
component: NoticeRegisterComponent,
},
{
path: 'stations/:lineName',
component: StationListComponent,
},
];

@NgModule({
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { FormsModule } from '@angular/forms';
import { TermsOfServiceDialogComponent } from './terms-of-service-dialog/terms-of-service-dialog.component';
import { TrainService } from './train.service';
import trainRouter from 'server/src/routes/train';
import { StationListComponent } from './station-list/station-list.component';

@NgModule({
declarations: [
Expand All @@ -22,6 +23,7 @@ import trainRouter from 'server/src/routes/train';
LineSelectComponent,
NoticeRegisterComponent,
TermsOfServiceDialogComponent,
StationListComponent,
],
imports: [
BrowserModule,
Expand Down
9 changes: 9 additions & 0 deletions src/app/line-detail/line-detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@
<mat-icon>notifications</mat-icon>
</button>

<button
class="station-list-button"
routerLink="/stations/{{ line.linename }}"
mat-fab
color="primary"
>
<mat-icon>other_houses</mat-icon>
</button>

<button
class="refresh-button"
(click)="this.loadTrains()"
Expand Down
21 changes: 21 additions & 0 deletions src/app/station-list/station-list.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<mat-list>
<div mat-subheader>{{ this.line.label }}線 <{{ this.line.section }}></div>
<ng-container>
<mat-list-item *ngFor="let station of stations">
<mat-icon mat-list-icon>other_houses</mat-icon>
<!-- 駅名 -->
<div mat-line>{{ station.name }}</div>
</mat-list-item>
</ng-container>
</mat-list>

<div class="fabs">
<button
class="train-list-button"
routerLink="/lines/{{ line.linename }}"
mat-fab
color="primary"
>
<mat-icon>train</mat-icon>
</button>
</div>
11 changes: 11 additions & 0 deletions src/app/station-list/station-list.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.fabs {
z-index: 1000;
position: fixed;
bottom: 5%;
right: 2.5%;
}

.fabs button {
display: block;
margin-top: 1rem;
}
Loading

0 comments on commit b721a1b

Please sign in to comment.