Compare commits

...

1088 Commits

Author SHA1 Message Date
Irie Aoi cb218c435d lint 2020-12-11 03:08:20 +09:00
Irie Aoi db9d93ed90 OGPResolver https 2020-12-11 03:04:30 +09:00
Irie Aoi 69ec50a6c0 XtubeResolverTest 追従 2020-12-11 02:57:52 +09:00
Irie Aoi f408c23982 XtubeResolver HTMLが壊れているので説明の取得をコメントアウト 2020-12-11 02:57:42 +09:00
Irie Aoi 3d9179268f ToranoanaResolver 追従 2020-12-11 02:52:32 +09:00
Irie Aoi e1e4ffbdc8 PlurkResolver 追従 2020-12-11 02:49:48 +09:00
Irie Aoi 1febc0866d PixivResolver 追従 2020-12-11 02:49:08 +09:00
Irie Aoi eacc7bf5f8 NijieResolverTest 追従 2020-12-11 02:40:23 +09:00
Irie Aoi ed9307c078 KomifloResolverTest 追従 2020-12-11 02:38:33 +09:00
Irie Aoi 330facf974 KomifloResolver タグをsort 2020-12-11 02:38:22 +09:00
Irie Aoi 2778d34711 IwaraResolverTest 追従 2020-12-11 02:34:31 +09:00
Irie Aoi 8d53c0f175 IwaraResolver 説明をtrim 2020-12-11 02:34:22 +09:00
Irie Aoi c73141c1d3 FC2ContentsResolver OGP以上の情報が取れなくなったため削除 2020-12-11 02:31:55 +09:00
Irie Aoi a667767858 FanzaResolverTest 追従 2020-12-11 02:18:03 +09:00
Irie Aoi daa12d93a5 FanzaResolver 動画のタグと説明取得方法を改善 2020-12-11 02:17:47 +09:00
Irie Aoi 4b51f6dfec FanzaResolver PCゲームのタグ取得セレクタを修正 2020-12-11 01:49:24 +09:00
Irie Aoi 5a1560fef9 DLsiteResolverTest 追従 2020-12-11 01:40:39 +09:00
Irie Aoi 3b3fc6c973 DLsiteResolver タグをソート 2020-12-11 01:39:55 +09:00
Irie Aoi 21a7d3f9e7 update fixtures 2020-12-11 01:19:48 +09:00
dependabot[bot] 7bcf48c8bf
Bump nunomaduro/collision from 3.0.1 to 3.1.0 (#565) 2020-12-08 13:46:31 +00:00
dependabot[bot] 8f1a94b863
Bump dot-prop from 4.2.0 to 4.2.1 (#561) 2020-12-08 13:08:25 +00:00
dependabot[bot] 1b54af63ce
Bump facade/ignition from 1.16.3 to 1.16.4 (#567) 2020-12-08 13:04:43 +00:00
dependabot[bot] 3ba946ec11
Bump symfony/dom-crawler from 4.4.11 to 4.4.17 (#556) 2020-12-08 13:02:49 +00:00
dependabot[bot] 32e25a9f7a
Bump laravel/helpers from 1.2.0 to 1.4.0 (#548) 2020-12-07 23:33:42 +00:00
dependabot[bot] 31626f48d9
Bump barryvdh/laravel-ide-helper from 2.8.0 to 2.8.1 (#540) 2020-12-07 23:06:43 +00:00
dependabot[bot] 174d802edf
Bump league/csv from 9.6.0 to 9.6.1 (#541) 2020-12-07 22:51:57 +00:00
shibafu 9c9db69662
Merge pull request #558 from eai04191/fix-cien-resolver
Fix Cien resolver
2020-12-07 08:33:14 +09:00
Irie Aoi 8c5fdfb7f8 未使用のfixtureを削除 2020-12-06 19:37:56 +09:00
Irie Aoi c616800da1 投稿に使える画像があれば使う 2020-12-06 19:37:56 +09:00
Irie Aoi 6449094b78 JWTがついているときだけexpires_atを付与する 2020-12-06 19:37:56 +09:00
Irie Aoi 072b3a0910 Cien fixture 更新 2020-12-06 19:37:56 +09:00
shibafu 83d22b807f
Merge pull request #559 from shikorism/fix/xdebug-first-aid
CIでカバレッジ取りに使用するXdebugのバージョンを落とす
2020-12-05 10:01:38 +09:00
shibafu 914d92e545 CIでカバレッジ取りに使用するXdebugのバージョンを落とす 2020-12-03 21:20:23 +09:00
shibafu dcef270790
Merge pull request #554 from shikorism/fix/negative-margin-destroyer
ユーザーページでstatus alertを出した時に余白が無くて不恰好なのを修正
2020-11-21 15:50:23 +09:00
shibafu 5808ac58ee ユーザーページでstatus alertを出した時に余白が無くて不恰好なのを修正 2020-11-18 23:09:21 +09:00
shibafu b60932b6c5 add config for heroku 2020-11-13 23:39:42 +09:00
shibafu 28520007e4
Merge pull request #553 from shikorism/feature/332-discard-elapsed-time
「前回チェックインからの経過時間を記録しない」チェックインオプションの追加
2020-11-12 00:32:17 +09:00
shibafu 63af49ba70 概況計算でdiscard elapsed timeを考慮 2020-11-08 23:41:51 +09:00
shibafu 3825228344 discard elapsed timeフラグの立ったチェックインの表示対応 2020-11-08 23:07:51 +09:00
shibafu 855011c624 add discard_elapsed_time option 2020-11-08 15:38:54 +09:00
shibafu bb7b05435e add migration 2020-11-08 01:04:56 +09:00
shibafu 5c26e58c1d
Merge pull request #550 from shikorism/fix/239-actual-ejaculated-span
チェックインスパンの計算手段をWindow関数から相関サブクエリに変更
2020-11-07 17:26:19 +09:00
shibafu ddb11ee96c
Merge pull request #547 from shikorism/feature/realtime-checkin
日時指定を省略してチェックインする機能
2020-11-07 17:18:09 +09:00
shibafu 38c7755757 チェックインスパンの計算手段をWindow関数から相関サブクエリに変更 2020-11-06 09:12:25 +09:00
shibafu c0cfbe1bc4 日時指定を省略してチェックインする機能 2020-11-03 14:19:25 +09:00
shibafu 96bf90104e
Merge pull request #545 from shikorism/composer2
thanks prestissimo, goodbye!
2020-10-31 01:26:46 +09:00
shibafu 2bcd050fed thanks prestissimo, goodbye! 2020-10-31 01:06:06 +09:00
shibafu ea1483a90a
Merge pull request #538 from shikorism/fix/degrade-profile-stats
プロフィールページの概況が消えていたのを修正
2020-10-26 08:58:09 +09:00
shibafu 7e7d0f80c1 プロフィールページの概況が消えていたのを修正 2020-10-26 00:22:06 +09:00
shibafu 32398fea73
Merge pull request #536 from shikorism/fix/degrade-show-checkin
チェックイン個別ページのユーザープロフィールが半分消えているのを修正
2020-10-25 17:30:22 +09:00
shibafu 076e7d5d0d チェックイン個別ページのユーザープロフィールが半分消えているのを修正 2020-10-25 17:22:04 +09:00
dependabot[bot] 41c7679423
Bump symfony/css-selector from 4.4.11 to 4.4.15 (#523) 2020-10-25 07:55:53 +00:00
dependabot[bot] 486e5bad0a
Bump barryvdh/laravel-debugbar from 3.4.1 to 3.5.1 (#516) 2020-10-25 07:47:00 +00:00
dependabot[bot] a026897986
Bump laravel/framework from 6.18.35 to 6.19.1 (#533) 2020-10-25 07:36:53 +00:00
dependabot[bot] 96658ac34c
Bump http-proxy from 1.18.0 to 1.18.1 (#514) 2020-10-25 07:32:42 +00:00
dependabot[bot] 622964ec01
Bump symfony/http-kernel from 4.4.11 to 4.4.13 (#510) 2020-10-25 07:05:32 +00:00
shibafu 141067beab
Merge pull request #534 from shikorism/feature/refresh-navigations
プロフィールページ内タブのデザイン変更とヘッダーナビゲーションの再編
2020-10-25 16:04:21 +09:00
shibafu 61b83c18a7 ユーザー名のスタイル調整 2020-10-24 18:30:13 +09:00
shibafu 581ae56173 プロフィール内タブのデザイン調整 2020-10-24 15:40:11 +09:00
shibafu b50a15c109 ヘッダーナビゲーションの内容を再編 2020-10-24 15:07:46 +09:00
shibafu 060bdeef43 ヘッダーメニューに自アカウントのグラフ・オカズへのリンクを追加 2020-10-24 15:00:21 +09:00
shibafu be098c38cb ヘッダーのドロップダウンメニューの中身を別ファイルに分割 2020-10-24 14:53:12 +09:00
shibafu d7d2bc2397 プロフィールページのタブ周りのデザインを刷新 2020-10-24 14:32:30 +09:00
shibafu 0f435c09b3
Merge pull request #479 from shikorism/feature/463-update-fixture
Fixture updater
2020-10-24 11:57:12 +09:00
shibafu 16071f7cff
Merge pull request #531 from shikorism/fix/robots-ignore-non-plain-response
robots.txt取得時、text/plain以外の応答は失敗扱いにする
2020-10-21 20:47:19 +09:00
shibafu a22f41766a remove unused use 2020-10-19 09:18:24 +09:00
shibafu 552ff421dd file_get_contentsを直接使うのをやめよう運動 2020-10-19 09:17:49 +09:00
shibafu f8952474b5 MetadataResolverのFixtureを更新する仕組みを追加 2020-10-19 09:17:49 +09:00
shibafu 3fd62dcd6f robots.txt取得時、text/plain以外の応答は失敗扱いにする 2020-10-17 16:54:00 +09:00
shibafu 4360144d6f
Merge pull request #530 from shikorism/fix/cien-jwt
Ci-en: JWTから有効期限を取得する
2020-10-17 16:20:18 +09:00
shibafu e74a9675ce Ci-en: JWTから有効期限を取得する 2020-10-17 14:01:28 +09:00
shibafu 0bc546ac64
Merge pull request #498 from shikorism/fix/card-throttle-in-guest
ゲストアクセス時のレートリミットを厳しめにする
2020-08-25 22:29:34 +09:00
shibafu 95ed292f4f ゲストアクセス時のレートリミットを厳しめにする 2020-08-25 22:07:54 +09:00
shibafu 032533666d
Merge pull request #495 from shikorism/fix/middleware-order-in-stateful-api
Stateful APIのMiddleware順序を調整
2020-08-25 01:48:46 +09:00
shibafu 5fc8a22cca Stateful APIのMiddleware順序を調整 2020-08-23 16:56:35 +09:00
shibafu 3406b326f0
Merge pull request #494 from shikorism/fix/es5-error-workaround
ES5 User error class workaround
2020-08-23 15:40:40 +09:00
shibafu 7cf1a362ac
Merge pull request #493 from shikorism/fix/491-fetch-card-error
カード情報の取得に失敗した時にちゃんと処理を中断させる
2020-08-23 15:18:40 +09:00
shibafu 7708e705cc ES5 User error class workaround 2020-08-23 15:08:13 +09:00
dependabot[bot] 494eb7a17b
Bump @typescript-eslint/parser from 3.1.0 to 3.9.1 (#488) 2020-08-23 04:45:04 +00:00
shibafu 24a74c4c2c カード情報の取得に失敗した時にちゃんと処理を中断させる 2020-08-23 13:43:31 +09:00
shibafu d1f14ed271
Merge pull request #492 from shikorism/fix/489-fix-copipe
チェックイン編集・流用時のフラグ周りの動作修正
2020-08-23 13:12:44 +09:00
shibafu 16d71a1621 オカズ流用時に非公開フラグを継承 2020-08-23 13:06:11 +09:00
shibafu c956a96605 チェックイン編集時に非公開フラグが維持されていないバグの修正 2020-08-23 13:02:27 +09:00
dependabot[bot] f301c56a1a
Bump barryvdh/laravel-debugbar from 3.3.3 to 3.4.1 (#487) 2020-08-23 02:26:13 +00:00
dependabot[bot] 2c2b17653e
Bump barryvdh/laravel-ide-helper from 2.7.0 to 2.8.0 (#486) 2020-08-23 02:21:20 +00:00
dependabot[bot] 569363c72e
Bump laravel/framework from 6.18.26 to 6.18.35 (#482) 2020-08-23 02:18:32 +00:00
dependabot[bot] 3ba3165b93
Bump @types/chart.js from 2.9.23 to 2.9.24 (#483) 2020-08-23 02:17:30 +00:00
dependabot[bot] 083373ad7d
Bump laravel/tinker from 2.4.1 to 2.4.2 (#485) 2020-08-23 02:17:04 +00:00
dependabot[bot] 2b109163fc
Bump anhskohbo/no-captcha from 3.2.0 to 3.2.1 (#484) 2020-08-23 02:16:04 +00:00
dependabot[bot] beca7fb0c6
Bump stylelint-config-recess-order from 2.0.4 to 2.1.0 (#475) 2020-08-23 01:37:15 +00:00
dependabot[bot] fa733417dd
Bump stylelint from 9.10.1 to 13.6.1 (#412) 2020-08-23 01:27:31 +00:00
dependabot[bot] 7dca83d12a
Bump mockery/mockery from 1.4.0 to 1.4.2 (#467) 2020-08-22 18:29:27 +00:00
dependabot[bot] d8c88fab63
Bump symfony/css-selector from 4.4.10 to 4.4.11 (#446) 2020-08-22 18:28:43 +00:00
dependabot[bot] 9bac56f912
Bump symfony/dom-crawler from 4.4.10 to 4.4.11 (#447) 2020-08-22 18:27:21 +00:00
dependabot[bot] 28c0060679
Bump facade/ignition from 1.16.1 to 1.16.3 (#434) 2020-08-22 18:18:24 +00:00
dependabot[bot] b5af600336
Bump symfony/thanks from 1.2.8 to 1.2.9 (#426) 2020-08-22 18:16:30 +00:00
shibafu 301fc83e7e
Merge pull request #468 from shikorism/feature/per-host-resolve-control
リモートホストごとの同時アクセス制御とメタデータ取得ポリシー制御
2020-08-22 09:37:09 +09:00
shibafu 3bb2b9afe0
Merge pull request #465 from shikorism/feature/metadata-error
メタデータ取得エラーの記録とリトライ制限の適用
2020-08-22 09:34:58 +09:00
shibafu 4e521baf56
Merge pull request #442 from shikorism/feature/300-incoming-webhook
Incoming webhook
2020-08-21 01:11:00 +09:00
shibafu 59e4cb8d91 throttleをルートごとに別々にかける
refs #474
2020-08-20 20:49:01 +09:00
shibafu d0fcbd79ca fix import 2020-08-20 09:26:02 +09:00
shibafu c680cd8d8e Merge branch 'develop' into feature/300-incoming-webhook
# Conflicts:
#	package.json
#	webpack.mix.js
#	yarn.lock
2020-08-20 09:24:28 +09:00
shibafu 2d42f48bea
Merge pull request #440 from shikorism/dependabot/npm_and_yarn/date-fns-2.15.0
Bump date-fns from 1.30.1 to 2.15.0
2020-08-20 00:09:48 +09:00
shibafu a54d57827f fix format pattern 2020-08-19 23:55:26 +09:00
dependabot[bot] f8a5cc5d54
Bump date-fns from 1.30.1 to 2.15.0
Bumps [date-fns](https://github.com/date-fns/date-fns) from 1.30.1 to 2.15.0.
- [Release notes](https://github.com/date-fns/date-fns/releases)
- [Changelog](https://github.com/date-fns/date-fns/blob/master/CHANGELOG.md)
- [Commits](https://github.com/date-fns/date-fns/compare/v1.30.1...v2.15.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-19 14:53:18 +00:00
shibafu 6f8c81cef2
Merge pull request #473 from shikorism/feature/365-csv-flags
非公開フラグ、センシティブフラグのCSVインポート・エクスポート対応
2020-08-19 23:19:19 +09:00
shibafu 915b575e6e 非公開フラグ、センシティブフラグのCSV入力対応 2020-08-19 21:25:07 +09:00
shibafu 27e9a86be8 add test 2020-08-19 21:24:47 +09:00
shibafu 3015f82611 非公開フラグ、センシティブフラグのCSV出力対応 2020-08-19 09:47:54 +09:00
dependabot[bot] d894897b82
Bump @types/chart.js from 2.9.22 to 2.9.23 (#461) 2020-08-18 23:45:16 +00:00
shibafu 0ccb04c651
Merge pull request #470 from shikorism/feature/326-react-checkin-form
チェックインフォームをReactで作り替える
2020-08-18 14:07:03 +09:00
shibafu acc3c05c86 fix lint-staged extension 2020-08-17 20:06:07 +09:00
shibafu 4405a2b526 concat import 2020-08-17 18:23:16 +09:00
shibafu 7d8969e5f1 esModuleInterop 2020-08-17 18:17:38 +09:00
shibafu 8641f26350 fix eslint 2020-08-17 16:19:14 +09:00
shibafu 432c2bf4d5 rm vue 2020-08-17 16:11:31 +09:00
shibafu 228b1cdaaa fix いろいろ 2020-08-17 16:08:35 +09:00
shibafu f37a9c79f4 update package.json 2020-08-17 16:02:39 +09:00
shibafu 6968ca7333 やるだけ.tsx 2020-08-17 16:00:04 +09:00
shibafu 867cafa26b
Merge pull request #469 from shikorism/fix/466-mobatwi
Twitterのサブドメイン対応用Resolverを追加
2020-08-16 16:17:00 +09:00
shibafu 04d546b1f0 Twitterのサブドメイン対応用Resolverを追加 2020-08-16 14:38:35 +09:00
shibafu e961a2d4b4 export defaultは微妙 2020-08-13 01:57:09 +09:00
shibafu 064cfff211 wip 2020-08-13 00:38:26 +09:00
shibafu 969ddb94a9 タグの確定時に空白文字を置換する
from 978eccd643
2020-08-12 23:06:17 +09:00
shibafu ae79f0225e CSSをどうにかするのを諦める 2020-08-12 23:05:38 +09:00
shibafu 196819270b wip 2020-08-12 22:48:23 +09:00
shibafu 45fd630e1a fix test 2020-08-12 22:05:56 +09:00
shibafu b71b7e5cb2 リモートホストごとの同時アクセス制御とメタデータ取得ポリシー制御 2020-08-11 00:17:10 +09:00
shibafu f715e7feee add migration and model 2020-08-10 20:38:38 +09:00
shibafu ca070e773a add test 2020-08-10 15:57:02 +09:00
shibafu da7be61698 Don't report circuit break exception 2020-08-10 13:40:40 +09:00
shibafu c372c11867 rm Log 2020-08-10 13:40:03 +09:00
shibafu 578b9934f5 メタデータ取得エラーの記録とリトライ制限の適用 2020-08-10 13:32:47 +09:00
shibafu 4acebcec7e Add metadata error attrs migration 2020-08-10 12:25:00 +09:00
shibafu 0ca16459a4
Merge pull request #464 from shikorism/fix/transact-checkin
EjaculationControllerでトランザクションを使う
2020-08-10 11:48:23 +09:00
shibafu b99930e145 EjaculationControllerでトランザクションを使う 2020-08-10 00:10:06 +09:00
shibafu 8093b22981
Merge pull request #462 from shikorism/fix/454-ogpresolver-cookie
OGPResolver: リダイレクト時にCookieを維持させる
2020-08-09 12:35:28 +09:00
shibafu 8cde943cf8 つらい 2020-08-09 11:55:57 +09:00
shibafu 1c6959bfcb is_private, is_too_sensitiveにfalseを明示的に指定すると真になってた 2020-08-09 11:06:42 +09:00
shibafu 73c64f0f27 use Validator::validate() 2020-08-09 10:59:44 +09:00
shibafu 7aa11275cc OGPResolver: リダイレクト時にCookieを維持させる 2020-08-08 18:32:38 +09:00
shibafu e6950a5dfb
Merge pull request #460 from shikorism/replace-jquery-tissue-plugin
Replace jquery tissue plugin
2020-08-08 16:41:48 +09:00
shibafu 134983d13d JSON APIリクエスト時に例外が発生したら、常にJSONでレスポンスする 2020-08-08 15:17:32 +09:00
shibafu 35aa7b3916 Rename ejaculation scope "public" -> "visibleToTimeline" 2020-08-08 14:19:57 +09:00
shibafu 0587a0f1d4 use transaction 2020-08-07 23:22:01 +09:00
shibafu 969bc79cbc 削除確認モーダルのsubmit処理を変更 2020-08-07 22:35:49 +09:00
shibafu 723587b0ac deleteCheckinModalの中身でなるべくjQueryを使わないようにした 2020-08-07 09:50:01 +09:00
shibafu 23189b76e4 deleteCheckinModalをVanilla化 2020-08-07 01:02:36 +09:00
shibafu 8a0a29feef linkCardをVanilla化 2020-08-07 00:27:15 +09:00
hina 2f928a29e1 yarn.lock 2020-08-07 00:09:21 +09:00
Hinaloe 62a3e883e1
Merge branch 'develop' into feature/300-incoming-webhook 2020-08-06 23:28:30 +09:00
dependabot[bot] 65077571e7
Bump eslint from 7.2.0 to 7.6.0 (#456) 2020-08-06 14:24:53 +00:00
shibafu a4fdd220ba pageSelectorをVanilla化 2020-08-06 23:17:25 +09:00
shibafu a52211758e
Merge pull request #459 from shikorism/fetch
Fetch APIを使う
2020-08-06 23:14:28 +09:00
shibafu 1482c33448 jQuery.ajax向けのCSRF Token設定を削除 2020-08-06 21:32:13 +09:00
shibafu 7c32ab068d jQuery.ajaxの村を滅ぼした 2020-08-06 21:32:12 +09:00
shibafu 3a1ec763ea fetch: 共通headerが送られてなかった 2020-08-06 21:15:36 +09:00
shibafu 77620c1699 x-csrf-tokenが送られねえ 2020-08-06 09:53:50 +09:00
shibafu 126e44bcd9 今日からjQuery.ajax禁止な 2020-08-06 09:09:53 +09:00
shibafu 422891e237 fetch wrapper 2020-08-06 09:05:31 +09:00
shibafu 081dd8da28
Merge pull request #457 from shikorism/fix/source-map-in-dev
SourceMapが欲しい
2020-08-06 02:02:33 +09:00
shibafu 87c97d27a8 generateForProduction: false 2020-08-06 01:27:47 +09:00
shibafu 8f1a4d3e88 これでいけるじゃん 2020-08-06 01:26:11 +09:00
shibafu 82bb10ae24 SourceMapが欲しい 2020-08-06 01:10:13 +09:00
dependabot[bot] 54e112fa57
Bump elliptic from 6.5.2 to 6.5.3 (#449) 2020-08-01 10:11:59 +00:00
shibafu a63c39a56f
Merge pull request #452 from shikorism/fix/451-atomic-metadata-resolve
Metadata解決処理をトランザクション内で実行する
2020-08-01 18:48:13 +09:00
shibafu f8a93fdf45 Metadata解決処理をトランザクション内で実行する 2020-08-01 18:39:43 +09:00
shibafu 978d54cf12
Merge pull request #443 from shikorism/fix/ignore-resolve-self
Tissue内のURLに対するメタデータ取得は拒否する
2020-08-01 18:38:14 +09:00
shibafu 43ed36ccb7
Merge pull request #450 from shikorism/feature/312-tag-normalize
正規化したタグ名で検索
2020-08-01 16:10:14 +09:00
shibafu 18ae64a870 テストしたいのはNFDだった 2020-07-31 23:19:35 +09:00
shibafu b5901f26bf add test 2020-07-31 23:10:54 +09:00
shibafu c9efcb538c add extension requirements 2020-07-31 22:21:31 +09:00
shibafu 561c9d028d 検索時にはtags.normalized_nameを使う 2020-07-30 23:12:29 +09:00
shibafu d18f245129 Docker: use php-intl 2020-07-30 23:04:53 +09:00
shibafu e2c43fef80 tags.normalized_name 2020-07-30 22:42:10 +09:00
shibafu c7aa002625 なんもわからんわー 2020-07-30 00:46:33 +09:00
shibafu 66322dfec0 Webhookチェックインをお惣菜コーナーに流す 2020-07-24 17:51:48 +09:00
shibafu fcdc00f165 Webhookからのチェックインであることを明示 2020-07-24 16:31:43 +09:00
shibafu e2ba3581f9 add test 2020-07-24 13:56:06 +09:00
shibafu d58afc0324 quirksはクソ 2020-07-24 12:42:11 +09:00
dependabot[bot] d69fe6a22a
Bump laravel/framework from 6.18.25 to 6.18.26 (#444)
Bumps [laravel/framework](https://github.com/laravel/framework) from 6.18.25 to 6.18.26.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/7.x/CHANGELOG-6.x.md)
- [Commits](https://github.com/laravel/framework/compare/v6.18.25...v6.18.26)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-24 12:41:43 +09:00
shibafu ef18d26b5d add ejaculations.checkin_webhook_id 2020-07-24 12:12:42 +09:00
shibafu 94446e0174 use softdelete 2020-07-24 12:02:27 +09:00
shibafu d3ecfd1fb8 fix empty check 2020-07-24 12:00:17 +09:00
shibafu 08ab0c6543 URL間違えてんじゃねーか 2020-07-23 23:22:11 +09:00
shibafu bbbea73a05 Webhook識別名重複チェック 2020-07-23 22:57:21 +09:00
shibafu 059c6d69cf Webhook作成数を制限 2020-07-23 22:36:08 +09:00
shibafu 08e12cd218 impl settings page 2020-07-23 22:26:34 +09:00
shibafu 134a11ad51
Merge pull request #445 from Al-aighumaisa/replace-whitespace-in-tag
タグの確定時に空白文字を置換する
2020-07-23 18:35:36 +09:00
مرزم اليَغميصاء 978eccd643 タグの確定時に空白文字を置換する
Closes #414.
2020-07-23 15:38:55 +09:00
shibafu 0a9920b11c さすがにServiceからHttpExceptionは雑すぎたか 2020-07-23 13:08:20 +09:00
shibafu 16b5fb3533 Tissue内のURLに対するメタデータ取得は拒否する 2020-07-21 23:39:48 +09:00
shibafu 35dea402ab add api document 2020-07-21 23:18:39 +09:00
shibafu ab960cda7c fix validation 2020-07-21 22:55:11 +09:00
shibafu e6252c49d1 date/timeをchecked_in_atに統合 2020-07-21 00:29:48 +09:00
shibafu de07e950f2 add POST /api/webhooks/checkin/{id} 2020-07-19 23:04:10 +09:00
shibafu 5926c6e640 add checkin_webhooks table 2020-07-19 18:39:19 +09:00
shibafu 034a47cd25
Merge pull request #439 from shikorism/fix/robots-txt
update robots.txt
2020-07-18 00:22:46 +09:00
shibafu 45645d9ae5 2020-07-17 22:23:37 +09:00
shibafu 73b63a1f39 update robots.txt 2020-07-17 21:46:25 +09:00
shibafu c5ab67d547
Merge pull request #436 from shikorism/feature/sentry
Add Sentry integration
2020-07-16 22:23:39 +09:00
shibafu 19d4ba5e40 Add Sentry integration 2020-07-16 22:11:42 +09:00
dependabot[bot] 6c3bcd57c5
Bump symfony/dom-crawler from 4.4.9 to 4.4.10 (#407) 2020-07-14 14:04:22 +00:00
dependabot[bot] ce0d9e7163
Bump eslint-plugin-prettier from 3.1.3 to 3.1.4 (#424) 2020-07-14 14:03:45 +00:00
dependabot[bot] 26f07e2b54
Bump friendsofphp/php-cs-fixer from 2.16.3 to 2.16.4 (#425) 2020-07-14 14:03:16 +00:00
dependabot[bot] 405a968ad8
Bump laravel/tinker from 2.4.0 to 2.4.1 (#427) 2020-07-14 14:02:52 +00:00
dependabot[bot] 9c6990979a
Bump laravel/framework from 6.18.23 to 6.18.25 (#432) 2020-07-14 14:02:31 +00:00
shibafu d83516f394
Merge pull request #430 from shikorism/fix/429-fanza-cookie
FANZA: 年齢認証Cookieを送信する
2020-07-09 00:33:09 +09:00
shibafu b232279c25 FANZA: 年齢認証Cookieを送信する 2020-07-09 00:22:43 +09:00
dependabot[bot] a04faa7001
Bump laravel/framework from 6.18.20 to 6.18.23 (#422) 2020-07-03 06:39:15 +00:00
dependabot[bot] 831c099247
Bump fideloper/proxy from 4.3.0 to 4.4.0 (#418) 2020-07-03 06:27:08 +00:00
dependabot[bot] 48815eed89
Bump guzzlehttp/guzzle from 6.5.4 to 6.5.5 (#411) 2020-07-03 05:22:51 +00:00
dependabot[bot] dc65645269
Bump @types/chart.js from 2.9.21 to 2.9.22 (#416) 2020-07-03 05:22:14 +00:00
dependabot[bot] d9fc2a4fca
Bump phpunit/phpunit from 8.5.6 to 8.5.8 (#419) 2020-07-03 05:21:25 +00:00
shibafu 5215398149
Merge pull request #423 from shikorism/fix/old-narou
古いなろう作品のIDにマッチングするように
2020-07-03 09:22:31 +09:00
Hinaloe 7afcf3f339
古いなろう作品のIDがマッチしていない 2020-07-02 00:20:35 +09:00
dependabot[bot] 261e27a3eb
Bump vue-property-decorator from 8.3.0 to 9.0.0 (#415) 2020-06-21 06:51:53 +00:00
dependabot[bot] 9db8fe78bb
Bump symfony/css-selector from 4.4.9 to 4.4.10 (#404) 2020-06-17 14:16:51 +00:00
dependabot[bot] 688f24193f
Bump symfony/thanks from 1.2.7 to 1.2.8 (#408) 2020-06-17 14:16:07 +00:00
dependabot[bot] dc055c9017
Bump phpunit/phpunit from 8.5.5 to 8.5.6 (#409) 2020-06-17 14:15:24 +00:00
dependabot[bot] 28e7497e53
Bump laravel/framework from 6.18.19 to 6.18.20 (#410) 2020-06-17 11:31:11 +00:00
dependabot[bot] 06a5bfac6b
Bump laravel/framework from 6.18.18 to 6.18.19 (#403) 2020-06-12 00:27:23 +00:00
dependabot[bot] 9a94f2ce42
Bump stylelint-config-recess-order from 2.0.3 to 2.0.4 (#399) 2020-06-09 00:01:45 +00:00
shibafu 43e22045ae
Merge pull request #396 from shikorism/fix/lint-staged
[fix] lint-staged のglobパターンが誤ってた
2020-06-07 23:20:49 +09:00
shibafu 4fbb047485
Merge pull request #397 from shikorism/lang/auth
auth言語ファイルの追加
2020-06-07 23:20:20 +09:00
hina c28967a5ae
言語ファイルの追加 2020-06-07 21:27:49 +09:00
hina a3e687bdb4
[fix] lint-staged のglobパターンが誤ってた 2020-06-07 19:34:27 +09:00
dependabot[bot] 6b15dcaef3
Bump resolve-url-loader from 2.3.2 to 3.1.1 (#372) 2020-06-07 08:40:16 +00:00
dependabot[bot] f28043e192
Bump sass from 1.25.0 to 1.26.8 (#388) 2020-06-07 08:17:02 +00:00
dependabot[bot] 79b873308a
Merge pull request #394 from shikorism/dependabot/npm_and_yarn/websocket-extensions-0.1.4 2020-06-07 08:07:50 +00:00
dependabot[bot] ecaa6e8110
Bump symfony/css-selector from 4.4.8 to 4.4.9 (#385) 2020-06-06 14:41:07 +00:00
dependabot[bot] 9fd0f0774d
Bump websocket-extensions from 0.1.3 to 0.1.4
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-06 13:36:06 +00:00
shibafu d0edea659e
Merge pull request #393 from shikorism/add-eslint
eslintをいれる
2020-06-06 20:21:57 +09:00
hina b9ed86b69a
@typescript-eslint/no-non-null-assertion を黙らせる 2020-06-06 19:12:00 +09:00
hina 2693d340c6
allowed underscore prefixed unused var 2020-06-06 18:40:49 +09:00
hina b909035fe8
disable @typescript-eslint/explicit-module-boundary-types 2020-06-06 18:11:49 +09:00
hina b908351a35
errorをつぶす 2020-06-06 18:03:51 +09:00
hina edd7a6f4c8
とりあえず一旦これで自動修正 2020-06-06 18:01:56 +09:00
hina 334c810b8d
リーナスも80文字は短いみたいなこといってたし120文字でええやろ 2020-06-06 17:51:17 +09:00
hina 51d9b74697
duplicate 2020-06-06 17:45:26 +09:00
hina c8c278653a
eslintの仮構成 2020-06-06 17:37:01 +09:00
Hinaloe d3592f9fea
Merge pull request #391 from shikorism/tsf
全フロントエンドコードのTypeScript化
2020-06-06 17:03:03 +09:00
shibafu a67a6a8be9 型を付ける音「カタカタ...」 2020-06-06 16:33:49 +09:00
shibafu 57c6eff442
Merge pull request #390 from shikorism/moment-locale
JSバンドルからMomentを除去する
2020-06-06 16:32:48 +09:00
hina 5d16c3b680
moment自体をexternalsで追い出す 2020-06-06 15:38:40 +09:00
hina aae9e0c502
草をうつす 2020-06-06 07:11:56 +09:00
hina 2a988275f3
Add moment-locales-webpack-plugin 2020-06-06 06:48:00 +09:00
hina 350360e2a9
D3をchartのチャンクに含める 2020-06-06 06:47:59 +09:00
dependabot[bot] 9aa3bb43d3
Merge pull request #383 from shikorism/dependabot/composer/symfony/dom-crawler-4.4.9 2020-06-05 16:04:59 +00:00
dependabot[bot] d0966e14ea
Bump symfony/dom-crawler from 4.4.8 to 4.4.9
Bumps [symfony/dom-crawler](https://github.com/symfony/dom-crawler) from 4.4.8 to 4.4.9.
- [Release notes](https://github.com/symfony/dom-crawler/releases)
- [Changelog](https://github.com/symfony/dom-crawler/blob/master/CHANGELOG.md)
- [Commits](https://github.com/symfony/dom-crawler/compare/v4.4.8...v4.4.9)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-05 15:59:15 +00:00
dependabot[bot] 9389593c3a
Merge pull request #381 from shikorism/dependabot/composer/laravel/framework-6.18.18 2020-06-05 15:56:08 +00:00
dependabot[bot] 037cfdfba9
Merge pull request #370 from shikorism/dependabot/npm_and_yarn/bootstrap-4.5.0 2020-06-05 15:53:57 +00:00
dependabot[bot] c559237ffd
Bump laravel/framework from 6.18.15 to 6.18.18
Bumps [laravel/framework](https://github.com/laravel/framework) from 6.18.15 to 6.18.18.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/7.x/CHANGELOG-6.x.md)
- [Commits](https://github.com/laravel/framework/compare/v6.18.15...v6.18.18)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-03 05:12:01 +00:00
dependabot[bot] 6c5332081c
Merge pull request #375 from shikorism/dependabot/composer/symfony/thanks-1.2.7 2020-06-02 14:53:38 +00:00
dependabot[bot] 204a0b2b70
Merge pull request #379 from shikorism/dependabot/composer/guzzlehttp/guzzle-6.5.4 2020-06-02 14:52:32 +00:00
dependabot[bot] b66896632a
Bump bootstrap from 4.4.1 to 4.5.0
Bumps [bootstrap](https://github.com/twbs/bootstrap) from 4.4.1 to 4.5.0.
- [Release notes](https://github.com/twbs/bootstrap/releases)
- [Commits](https://github.com/twbs/bootstrap/compare/v4.4.1...v4.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-02 14:48:12 +00:00
shibafu 4bac437d39
Merge pull request #374 from shikorism/dependabot/npm_and_yarn/types/jquery-3.3.38
Bump @types/jquery from 3.3.31 to 3.3.38
2020-06-02 23:46:04 +09:00
dependabot[bot] e4e065c614
Bump guzzlehttp/guzzle from 6.5.3 to 6.5.4
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/6.5.4/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/6.5.3...6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-02 14:17:34 +00:00
dependabot[bot] 5284b93d40
Bump symfony/thanks from 1.2.5 to 1.2.7
Bumps [symfony/thanks](https://github.com/symfony/thanks) from 1.2.5 to 1.2.7.
- [Release notes](https://github.com/symfony/thanks/releases)
- [Commits](https://github.com/symfony/thanks/compare/v1.2.5...v1.2.7)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-02 14:09:23 +00:00
dependabot[bot] f6fe04b766
Bump @types/jquery from 3.3.31 to 3.3.38
Bumps [@types/jquery](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jquery) from 3.3.31 to 3.3.38.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jquery)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-02 14:08:03 +00:00
shibafu 5f7a25e1b8
Merge pull request #368 from shikorism/chore/install-depandabot
dependabotのセットアップ
2020-06-02 23:06:38 +09:00
Hinaloe b71ee87691
Create dependabot.yml 2020-06-02 22:58:11 +09:00
shibafu 83b0ccf770
Merge pull request #367 from shikorism/feature/user-agent
外部へのHTTPリクエストに独自のUser-Agentを付与する
2020-06-02 22:51:43 +09:00
shibafu 77e83e48d3 yamlはクソ 2020-06-02 22:41:00 +09:00
shibafu c93106cab9 ふぁっきゅー 2020-06-02 22:40:00 +09:00
shibafu 4c04deb80f 外部へのHTTPリクエストに独自のUser-Agentを付与する 2020-06-02 22:20:26 +09:00
shibafu da8af95043 管理画面のお知らせのリンクもおかしかった 2020-05-25 00:57:52 +09:00
shibafu 9fcf9cd49e
Merge pull request #362 from shikorism/fix/checkin-user-link
チェックインのユーザーリンクのパラメータ名がおかしいのを修正
2020-05-24 22:43:47 +09:00
shibafu b5a72e33eb チェックインのユーザーリンクのパラメータ名がおかしいのを修正 2020-05-24 22:37:23 +09:00
shibafu 36c8d84555 オカズページの存在忘れてた 2020-05-24 21:44:18 +09:00
shibafu ced289b95d
Merge pull request #358 from shikorism/feature/remake-user-page
グラフページの再編
2020-05-24 21:23:23 +09:00
shibafu 40f45da282
Merge pull request #356 from shikorism/feature/302-bookmarklet
ブックマークレット等の案内ページ
2020-05-24 21:23:06 +09:00
shibafu 0218035aeb
Merge pull request #359 from shikorism/fix/ej-source-nonnull
ejaculations.sourceはNULL非許容にする
2020-05-24 21:22:13 +09:00
shibafu 1a3cead932 fix test 2020-05-24 19:50:51 +09:00
shibafu f3a5644a32 スコープの簡略化 2020-05-24 19:42:16 +09:00
shibafu e2f01561a8 ejaculations.sourceはNULL非許容にする 2020-05-24 19:39:24 +09:00
shibafu 8fb8677406 プロフィールトップに最近のシコ草を移動 2020-05-24 19:03:15 +09:00
shibafu 8ac65f1cc6 fix params 2020-05-24 18:32:45 +09:00
shibafu 5a3e41c82e fix class 2020-05-24 18:30:48 +09:00
shibafu c9fd46d408 共通化 2020-05-24 18:01:55 +09:00
shibafu ea2894cd4b 簡単なバリデーション 2020-05-24 17:49:22 +09:00
shibafu 2f4c61c900 rename view/route 2020-05-24 17:49:17 +09:00
shibafu 019412c72a グラフページを対象期間ごとに掘り下げる形に変更 2020-05-24 17:27:42 +09:00
shibafu 00f75f33cc Update README 2020-05-24 12:02:34 +09:00
shibafu 3a4c734bcf
Merge pull request #357 from shikorism/laravel-6
Laravel 6
2020-05-24 12:00:55 +09:00
shibafu ee7b7cf274 add parsedown 2020-05-24 00:28:19 +09:00
shibafu 34c4f13376 Laravel 6 2020-05-23 23:09:55 +09:00
shibafu 80590888df QUEUE_CONNECTION -> QUEUE_DRIVER (revert) 2020-05-23 22:31:17 +09:00
shibafu 74fee83f4e 非推奨のヘルパ関数の利用をやめる 2020-05-23 22:26:47 +09:00
shibafu a48fe596e1 Laravel 5.8 2020-05-23 22:17:07 +09:00
shibafu cb4dacdaf6 composer update忘れてた 2020-05-23 21:36:22 +09:00
shibafu a531e5c9bb Laravel 5.7 2020-05-23 21:34:54 +09:00
shibafu 17ee207281 change pagination file name for La5.6 2020-05-23 20:42:00 +09:00
shibafu 015bcaa563 Laravel 5.6 2020-05-23 20:32:24 +09:00
shibafu 36a2ab5fe2 ブックマークレット等の案内ページ 2020-05-23 17:37:53 +09:00
shibafu 3a05d2c9cc
Merge pull request #354 from shikorism/feature/319-csv-import
チェックインデータのインポート
2020-05-23 16:35:31 +09:00
shibafu 948b517c4d add doc 2020-05-23 16:26:07 +09:00
shibafu cc0e0271b8 add test 2020-05-23 15:56:51 +09:00
shibafu 5af55fa6b4 fix typo 2020-05-23 15:39:28 +09:00
shibafu bd84effedc インポート可能な件数に上限を設ける 2020-05-23 15:35:36 +09:00
shibafu c0d62f5112 インポートしたデータを消せるようにする 2020-05-23 02:47:25 +09:00
shibafu 1853c28093
Merge pull request #355 from shikorism/fix/purge-squatters
未来のオカズはお惣菜として出さない
2020-05-22 23:57:34 +09:00
shibafu 77f4bbcfce 未来のオカズはお惣菜として出さない 2020-05-22 23:53:14 +09:00
shibafu fb5b34b239 strict_types 2020-05-22 23:12:41 +09:00
shibafu 531067fb9c 取り込み件数を出力 2020-05-22 22:11:49 +09:00
shibafu 3a2d0e67aa 半角スペースを含むタグは受け付けない 2020-05-22 00:27:32 +09:00
shibafu 54b6ff2282 インポートバッジ 2020-05-22 00:07:04 +09:00
shibafu 023446e0a8 CSVインポートのチェックインはお惣菜コーナーに表示しない 2020-05-21 23:58:58 +09:00
shibafu 8681c328d0 ejaculated_dateの重複エラーをcatch 2020-05-21 23:13:39 +09:00
shibafu fa4827f382 インポート処理のコントローラーとか実装 2020-05-21 22:33:27 +09:00
shibafu 15c462449f
Merge pull request #353 from shikorism/fix/csv-export-date-format
CSVエクスポートの日付書式が仕様と違っていた
2020-05-21 22:32:37 +09:00
shibafu 03b05a48cd CSVエクスポートの日付書式が仕様と違っていた 2020-05-21 22:28:34 +09:00
shibafu 1671070d0c Merge branch 'feature/319-csv-export' into develop 2020-05-20 21:56:37 +09:00
shibafu 9f047544b9
Merge pull request #352 from shikorism/feature/319-csv-export
チェックインデータのエクスポート
2020-05-20 21:49:23 +09:00
shibafu 988ad9d992 タグ出力数の上限 2020-05-20 21:42:22 +09:00
shibafu 5668296e7d add 気休め 2020-05-20 21:28:46 +09:00
shibafu 8a764c756c use custom control style 2020-05-20 21:07:11 +09:00
shibafu cf9df74ed3 Export checkin to CSV 2020-05-20 01:50:34 +09:00
shibafu e872964144
Merge pull request #344 from shikorism/feature/319-csv-importer
CheckinCsvImporter
2020-05-18 01:05:58 +09:00
shibafu 5db25ce017
Merge pull request #350 from shikorism/fix/unique-metadata-and-tags
metadata.urlをPKに、tags.nameをUNIQUEに設定
2020-05-16 17:07:50 +09:00
shibafu a58a206b86 metadata.urlをPKに、tags.nameをUNIQUEに設定 2020-05-16 17:01:14 +09:00
shibafu dcdd33925b
Merge pull request #348 from shikorism/fix/tag-to-metadata-assoc
Tag -> Metadata のリレーション設定
2020-05-16 15:29:39 +09:00
shibafu 552c2d4460 Tag -> Metadata のリレーション設定 2020-05-16 15:25:03 +09:00
shibafu c11bbbbff7
Merge pull request #331 from shikorism/fix/330-tag-dedup
メタデータのタグ重複対策
2020-05-16 15:00:51 +09:00
shibafu d33d7b58a4
Merge pull request #346 from shikorism/feature/maintenance-template
メンテナンス用ビューテンプレート
2020-05-16 15:00:42 +09:00
shibafu 2a50ee4f5b メンテナンス中はヘッダーにログイン等を表示しない 2020-05-16 14:47:17 +09:00
shibafu e9414517b9 メンテナンス用ビューテンプレート 2020-05-16 14:31:05 +09:00
shibafu ab9ecd6bfa
Merge pull request #345 from shikorism/fix/334-okazu-with-likes
/user/{name}/okazu にもいいねしたユーザーのアイコンを表示する
2020-05-14 01:26:55 +09:00
shibafu 59c6e4a52a /user/{name}/okazu にもいいねしたユーザーのアイコンを表示する 2020-05-14 01:18:14 +09:00
shibafu 0ca7b8b7e1 タグ列の番号飛びを許容 2020-05-14 00:31:03 +09:00
shibafu 882f239d58
Merge pull request #343 from shikorism/feature/integrate-metadata-resolve
メタデータの解決と保存の処理を統一
2020-05-14 00:02:51 +09:00
shibafu 4c3c5f18d2 メタデータの解決と保存の処理を統一 2020-05-10 18:50:03 +09:00
shibafu 1953143ab2
Merge pull request #341 from shikorism/lib/jquery-3.5.1
Bump jquery from 3.5.0 to 3.5.1
2020-05-10 16:31:00 +09:00
shibafu 8c2f7d4212 Bump jquery from 3.5.0 to 3.5.1 2020-05-10 16:19:32 +09:00
shibafu f2b91b71f8 Merge commit '631d2ea298f62788dd0a14c65f553e0d0ec8322c' into develop 2020-05-09 22:54:38 +09:00
dependabot[bot] ef6fd71cee
Merge pull request #336 from shikorism/dependabot/npm_and_yarn/jquery-3.5.0 2020-04-30 16:37:39 +00:00
dependabot[bot] 55fba9e2a2
Merge pull request #333 from shikorism/dependabot/npm_and_yarn/acorn-6.4.1 2020-04-30 16:36:35 +00:00
dependabot[bot] 7f4dd703db
Bump jquery from 3.4.1 to 3.5.0
Bumps [jquery](https://github.com/jquery/jquery) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.4.1...3.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-30 01:40:50 +00:00
dependabot[bot] 49bc254e8b
Bump acorn from 6.4.0 to 6.4.1
Bumps [acorn](https://github.com/acornjs/acorn) from 6.4.0 to 6.4.1.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/6.4.0...6.4.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-14 03:06:40 +00:00
shibafu 631ae820f3 add unique constraints 2020-02-22 16:46:15 +09:00
shibafu 77d3ebd452 重複タグの削除コマンド 2020-02-22 16:32:49 +09:00
shibafu 631d2ea298 タグを保存前に正規化する 2020-02-22 14:39:25 +09:00
shibafu cb0af4113d
Merge pull request #328 from shikorism/fix/325-tune-public-tl
トップページのお惣菜表示量をお惣菜コーナー1ページ分にする
2020-02-22 10:10:30 +09:00
shibafu 46ca276eab トップページのお惣菜表示量をお惣菜コーナー1ページ分にする 2020-02-20 22:10:04 +09:00
shibafu 41ce5229c7 これはいわゆるサービスなのではと思った 2020-02-18 02:09:01 +09:00
shibafu 6387d4e853 チェックインデータがCSVで投入されたことを記録できるようにした 2020-02-18 02:03:49 +09:00
shibafu 0a53199399 ネストをちょっと減らした 2020-02-16 23:21:17 +09:00
shibafu 794cdf2be6 argument unpackingの存在を思い出した 2020-02-16 23:17:07 +09:00
shibafu 84b955b195 continue 2はキモい 2020-02-16 23:09:30 +09:00
shibafu 12553321e1
Merge pull request #327 from shikorism/feature/xdebug-cli-wrapper
IDEからのデバッグ実行用ラッパーを追加
2020-02-16 22:51:44 +09:00
shibafu 24a5017334 タグ列のテスト 2020-02-16 22:43:18 +09:00
shibafu 272e7ecc61 エラーメッセージの統一感を高めた 2020-02-16 22:43:18 +09:00
shibafu 22845fe279 オカズリンクの判定テスト 2020-02-16 22:43:18 +09:00
shibafu 45eba30528 文字コード判定が上手く行かないケースがあったので、もう少し粘るようなアルゴリズムにした 2020-02-16 19:52:50 +09:00
shibafu 7259ee3647 ノートの改行コードを正規化 2020-02-16 19:52:50 +09:00
shibafu 3def26ddb9 Fixtureの改行コードをCRLFに変更 2020-02-16 19:52:50 +09:00
shibafu cef69a1545 ノートの文字数,改行などのチェック 2020-02-16 19:52:49 +09:00
shibafu ea59bcf150 日付形式と範囲のチェック 2020-02-16 19:52:33 +09:00
shibafu b29a82435c DataProviderを使ってテストを書いてみる 2020-02-16 19:52:30 +09:00
shibafu 67b697a600 Validatorを使いたくなった
日時のバリデーションが思うように動いていなかったので、カスタムルールを追加
2020-02-16 19:52:23 +09:00
shibafu 64065ce9e6 ざっくりとした処理を書いた 2020-02-16 19:52:19 +09:00
shibafu 8b9abe2d7b IDEからのデバッグ実行用ラッパーを追加 2020-02-16 19:34:45 +09:00
shibafu a5b9021e95
Merge pull request #324 from shikorism/fix/323-cien-pattern
Ci-enのドメインが変わっていたのでパターンに追加
2020-02-14 01:28:39 +09:00
shibafu 92e1131d20 全年齢向けドメインをパターンに追加 2020-02-13 00:18:58 +09:00
shibafu af02375475 Ci-enのドメインが変わっていたのでパターンに追加 2020-02-11 17:14:24 +09:00
shibafu 267eb48589
Merge pull request #322 from eai04191/feature/chart-nearest-fix
statsのグラフでカーソルに近い位置のツールチップを表示する
2020-02-11 00:20:03 +09:00
shibafu 38ae540009 文字コード判定と必須列のチェックまで 2020-02-04 01:44:16 +09:00
shibafu b2eed9a9c5 league/csvとopenpear/stream_filter_mbstringを依存関係に追加 2020-02-04 01:43:58 +09:00
eai04191 e7e4195a10 グラフでカーソルに近い位置のツールチップを表示する 2020-02-03 01:12:52 +09:00
shibafu 7968019e1c
Merge pull request #320 from shikorism/fix/318-profile-image-srcset
プロフィール画像のsrcsetを出力するヘルパーを追加
2020-01-29 22:52:51 +09:00
shibafu 1d0c51c284 rename argument 2020-01-29 08:38:13 +09:00
hina c9af8130f4
Add test for profileImageSrcSet 2020-01-29 03:41:14 +09:00
shibafu 9431cd5b5d プロフィール画像のsrcsetを出力するヘルパーを追加 2020-01-28 01:38:30 +09:00
shibafu 9f565798c0 Update npm packages 2020-01-26 17:08:36 +09:00
shibafu ef23f1b12e
Merge pull request #316 from shikorism/fix/295-trim-tag-space
タグの入力確定時にtrimする
2020-01-18 16:22:51 +09:00
shibafu 2edabfa38f タグの入力確定時にtrimする 2020-01-18 00:31:51 +09:00
shibafu ad65475037 Update composer packages 2020-01-18 00:11:03 +09:00
shibafu e429b2c054
Merge pull request #313 from eai04191/feature/resolver-dlsite-fix
DLsiteResolver の修正と更新
2020-01-10 09:43:24 +09:00
shibafu cec9ffc5ac
Merge pull request #314 from eai04191/feature/happy-new-year
著作権表示の更新
2020-01-10 09:01:08 +09:00
eai04191 07b315e8af 著作権表示の更新 2020-01-10 04:27:56 +09:00
eai04191 1948d5235e .btn_followを動的作成するようになったため削除クラス名を.add_followに変更 2020-01-10 03:58:24 +09:00
eai04191 78a255c1e3 fixtureを更新 2020-01-10 03:58:07 +09:00
shibafu d9cf5e54e3
Merge pull request #308 from shikorism/fix/force-testing-env
phpunit.xml内の環境変数を強制適用する
2019-12-30 16:04:03 +09:00
shibafu e7db04fd55
Merge pull request #309 from shikorism/fix/307-monthly-term
月間チェックイン回数グラフの期間セレクターが、直近1年の範囲しか選択できないバグを修正
2019-12-19 00:56:52 +09:00
shibafu 37a10b7354 月間チェックイン回数グラフの期間セレクターが、直近1年の範囲しか選択できないバグを修正 2019-12-16 22:56:11 +09:00
shibafu 170492b39d 本来テストにいらない処理を消す 2019-12-15 20:07:25 +09:00
shibafu ea3f2e595f phpunit.xml内の環境変数を強制適用する
docker-compose.ymlで指定した環境変数で上書きされてしまうため、こうする
2019-12-15 20:07:06 +09:00
shibafu 6ea360bc4e Merge branch 'master' into develop
cherry-pick部分のコンフリクト解消のため、ours merge
2019-12-12 20:35:47 +09:00
shibafu 251d7b9108
Merge pull request #299 from shikorism/feature/263-deactivate-account
アカウント削除
2019-12-12 20:25:58 +09:00
shibafu bba945113b deactivated_usersに登録されていることをチェックし忘れていた 2019-12-11 01:42:15 +09:00
shibafu 695f457505 テストをしましょう 2019-12-11 01:32:55 +09:00
shibafu 00345eedca
Merge pull request #303 from unarist/fix/ap-actor
MastodonのプロフィールURLをいい感じに表示する
2019-12-10 23:43:52 +09:00
shibafu 19ef4d2bbe
Merge pull request #305 from eai04191/feature/resolver-pixiv-en
PixivResolver 英語版に対応する
2019-12-10 23:42:15 +09:00
shibafu 6577a032e1
Merge pull request #304 from eai04191/feature/resolver-hentai-foundry
HentaiFoundryResolverを追加
2019-12-10 23:40:01 +09:00
eai04191 010a0a9c8f 英語版Pixivに対応する 2019-12-10 13:12:37 +09:00
eai04191 cdc6335a06 HentaiFoundryResolverを追加 2019-12-09 01:35:44 +09:00
eai04191 03633440a6 jakeasmith/http_build_urlを追加 2019-12-09 01:05:28 +09:00
unarist 67ae0e159f ActivityPubResolverはNoteだけ処理するように 2019-11-24 21:18:19 +09:00
shibafu 73ee9f108b 過去に使用されたユーザー名で登録できないようにする 2019-11-16 00:26:52 +09:00
shibafu f132955be7 アカウント削除画面の追加 2019-11-16 00:26:38 +09:00
shibafu 3420e053fc
Merge pull request #297 from shikorism/fix/admin-menu-in-sp-layout
管理画面へのリンクがモバイルで表示されないバグの修正
2019-11-14 21:15:09 +09:00
shibafu a01bc6989e 管理画面へのリンクがモバイルで表示されないバグの修正 2019-11-14 00:59:23 +09:00
shibafu a71aa0c3b6
Merge pull request #296 from shikorism/fix/295-drop-empty-value-tag
空文字列のタグは保存せず捨てる
2019-11-13 00:39:26 +09:00
shibafu 26be8a086e 空文字列のタグは保存せず捨てる 2019-11-09 23:19:28 +09:00
shibafu af5de3ee14
Merge pull request #294 from eai04191/feature/resolver-dlsite-affiliate-url
DLsiteResolver 新しいアフィリエイトURL構造に対応
2019-11-09 18:40:01 +09:00
eai04191 c8cee80144 冗長な評価を削除 2019-11-09 18:28:47 +09:00
eai04191 d8e170ff85 DLsiteの新しいアフィリエイトURL構造に対応 2019-11-08 05:36:40 +09:00
shibafu 9c101dfb7b
Merge pull request #293 from eai04191/feature/resolver-xtube-fix
XtubeResolver 修正
2019-11-05 08:17:34 +09:00
eai04191 12fd228e75 array_mapのcallbackをシンプルにする 2019-11-05 05:59:00 +09:00
eai04191 dc0eb0a548 tagの各要素をtrim()する 2019-11-04 14:24:09 +09:00
eai04191 16ed4482f4 OGPを吐くようになっていたのでOGPResolverでimageを取得するように変更 2019-11-04 14:23:30 +09:00
eai04191 57a847baf5 Update fixture 2019-11-04 14:01:42 +09:00
shibafu 332b6d7dd0 こっちのほうがマシ 2019-10-14 02:24:39 +09:00
shibafu 99a92c6106 チェックインの編集は本人のみ可能
(cherry picked from commit bcb5abb161)
2019-10-14 02:17:02 +09:00
shibafu bcb5abb161 チェックインの編集は本人のみ可能 2019-10-14 02:03:57 +09:00
shibafu 4ca6f00c1b
Merge pull request #288 from MitarashiDango/feature_tag_list
タグ一覧画面を追加
2019-10-11 00:33:25 +09:00
shibafu 7b8811b894
Merge pull request #281 from shikorism/fix/279-unauthorized-ajax-call
非ログイン状態でいいねしようとした時にログインを促す
2019-10-11 00:31:24 +09:00
shibafu c7e261d06b
Merge pull request #289 from shikorism/fix/nijie-unescape-after-json-decode
NijieResolver: JSONデコード後にHTMLエンティティのデコードを行う
2019-10-04 00:32:57 +09:00
shibafu b3c98613e7 テストの追加 2019-10-03 23:34:57 +09:00
shibafu f7a5948e8e
Merge pull request #292 from kb10uy/add-kb10uyshortstoryserverresolver
Kb10uyShortStoryServerResolver の追加
2019-10-03 23:22:22 +09:00
Yuu Kobayashi d1abca5416
成否判定を除去 2019-09-29 18:03:34 +09:00
Yuu Kobayashi 579708389a
Kb10uyShortStoryServerResolver とテストを追加 2019-09-29 11:33:05 +09:00
MitarashiDango 900e4c94a7 怒られたのでなおした... 2019-09-25 23:46:06 +09:00
MitarashiDango a434a45e4a タグ一覧の件数カウント条件を検索機能と揃える 2019-09-25 23:39:36 +09:00
shibafu e6657a0756
Merge pull request #291 from shikorism/develop
Release 20190925.2210
2019-09-25 22:20:39 +09:00
shibafu 4f6bb0ac15
Merge pull request #290 from eai04191/feature/resolver-pixiv-new-url
PixivResolver 新URL形式に対応
2019-09-25 22:07:55 +09:00
eai04191 e27a848b08 Pixiv新URL形式に対応 2019-09-25 08:42:28 +09:00
shibafu 8772facadf JSONデコード後にHTMLエンティティのデコードを行う
JSONデコード前にHTMLエンティティのデコードを行ってしまうと &quot; なども解除されてしまい、JSONとして不正な入力になる。
html_decode_entityのオプションで除外しても良いが、改行以外は一応JSONとして正当はなずなので、安全に倒してJSONとしてのデコードを済ませてから処理する。
2019-09-22 01:44:14 +09:00
MitarashiDango d5ee59825f 年齢確認ダイアログ表示時のブラーをタグ一覧へ適用させる 2019-09-19 00:09:41 +09:00
shibafu 4192f22af5
Merge pull request #287 from shikorism/fix/seiga-partially-tag-test
NicoSeigaResolverTest: ロックされているタグのみを検証する
2019-09-18 22:23:25 +09:00
MitarashiDango dd07940aea スマホ向けレイアウトへタグ一覧ボタンを追加 2019-09-16 14:02:19 +09:00
MitarashiDango 78bb7dae28 タグ一覧画面を追加 2019-09-16 13:24:22 +09:00
shibafu e4890f65ae 頻繁に変更される部分を完全一致判定してもきりがないので、ロックされているタグのみを検証する 2019-09-16 09:55:29 +09:00
shibafu 2454a24ee2
Merge pull request #286 from shikorism/username-hint
ユーザー名は変更できないことを明記する
2019-09-15 02:19:09 +09:00
shibafu 7858bd0a5f ユーザー名は変更不能である旨を登録画面に明記する 2019-09-15 02:10:54 +09:00
shibafu ce8855510c ユーザー名は変更不能です 2019-09-15 02:06:10 +09:00
shibafu c42a3d2657
Merge pull request #285 from shikorism/fix/hide-private-like-in-like-users
いいね非公開のユーザーが、チェックイン画面のいいね件数欄に露出してしまう不具合の修正
2019-09-15 02:02:42 +09:00
shibafu 7cb6dd4754 いいね非公開のユーザーが、チェックイン画面のいいね件数欄に露出する不具合の修正 2019-09-15 01:55:17 +09:00
shibafu bf1c4e7a21
Merge pull request #284 from eai04191/feature/resolver-fanza-improve
FanzaResolverに機能・テストを追加
2019-09-13 01:18:26 +09:00
shibafu 7a56072765 cosmetic change 2019-09-13 01:13:15 +09:00
eai04191 d6e0512dae 返り値の型を指定 2019-09-13 01:05:09 +09:00
eai04191 1edc70fc4c リンクのみをタグにするようにCSSセレクタを修正 2019-09-13 01:03:08 +09:00
shibafu a20f690cdd
Merge pull request #283 from eai04191/feature/resolver-fantiaResolver-improve
FantiaResolverを更新・テストを追加
2019-09-12 23:37:29 +09:00
shibafu eab901d56d
Merge pull request #282 from eai04191/feature/test-cienResolver
CienResolverのテストを追加
2019-09-12 23:05:58 +09:00
eai04191 8c88d60034 私が悪うございました 2019-09-12 11:58:21 +09:00
eai04191 599e3f9557 FanzaResolverに機能・テストを追加
動画、同人、電子書籍、PCゲームにてタグ取得に対応
2019-09-12 11:39:18 +09:00
eai04191 a9a0f3b99a FantiaResolverを更新・テストを追加
APIを見つけたのでAPIを使用するように
タグを追加
テストを追加
2019-09-12 06:56:28 +09:00
eai04191 5fc0c6c1b6 CienResolverのテストを追加 2019-09-12 05:26:03 +09:00
shibafu 5642e73391 401 Unauthorizedはよくないね 2019-09-12 00:00:34 +09:00
shibafu 92847fefe0
Merge pull request #280 from eai04191/feature/remove-status-200
不要な成否判定の削除
2019-09-10 23:40:21 +09:00
shibafu 178ed02d00
Merge pull request #276 from eai04191/feature/fix-resolver-deviantart
DeviantArtResolverのfixture・テストを更新
2019-09-10 23:40:01 +09:00
shibafu 3381965896
Merge pull request #270 from MitarashiDango/feature_add_okazu_spoiler
チェックインに対してセンシティブフラグを付与可能とする対応を実施
2019-09-10 23:39:45 +09:00
eai04191 dc8a70291d URL置換を削除 タグを追加
なんかもともと入っているurlが十分大きいので置換する必要がないことに気が付きました
2019-09-10 23:04:21 +09:00
shibafu a10acdd481 モックがHTTPステータスコードに応じた例外を投げるようにする 2019-09-10 22:35:36 +09:00
shibafu 2c4eaccf43 OGPResolverTestをrevert、Guzzleの例外を期待するように変更 2019-09-10 22:34:24 +09:00
shibafu 141d5ce77c
Merge pull request #278 from shikorism/feature/nicoseiga-tags
ニコニコ静画のタグを取得する & テストの追加
2019-09-10 20:20:30 +09:00
eai04191 ccade6ff9f 怒られたので直した(小学生並みの感想) 2019-09-10 07:33:29 +09:00
eai04191 033784bfc8 不要な成否判定の削除
ref: c0b76e5
2019-09-10 07:03:46 +09:00
eai04191 db39ee35c2 不要な判定の削除
ref: c0b76e5
2019-09-10 01:27:35 +09:00
shibafu fb6c1a0574
Merge pull request #277 from eai04191/feature/test-fix-xtube
XtubeResolverの取得方法を変更・テストを更新
2019-09-10 01:05:26 +09:00
shibafu 59aec2c038 不要な成否判定をやめる 2019-09-10 01:01:47 +09:00
shibafu d45898931a
Merge pull request #274 from eai04191/feature/test-fix-dlsiteresolver
DLsiteResolverのfixture・テストを更新
2019-09-10 00:52:53 +09:00
shibafu fb50881e74
Merge pull request #275 from eai04191/feature/test-fix-toranoanaresolver
ToranoanaResolverのfixture・テストを更新
2019-09-10 00:51:27 +09:00
shibafu 40fedf59d4 ニコニコ静画のテストの追加 2019-09-10 00:47:32 +09:00
shibafu b2014a3db7 ニコニコ静画のサムネイルをhttpsで取得する 2019-09-10 00:47:32 +09:00
shibafu f3a4f682a8 ニコニコ静画のタグを取得する 2019-09-10 00:47:31 +09:00
eai04191 c0b76e522b 200でなかったときのテストを削除
4xxや5xxの場合は`\GuzzleHttp\Exception\BadResponseException`が発生するので、今まであったelseのところには到達しなかった
2019-09-09 13:52:32 +09:00
eai04191 0f530099b4 データの取得方法をAPIからスクレイピングに変更
より多くのタグと高画質なサムネイルを取得するように変更
2019-09-09 13:51:07 +09:00
eai04191 eecace33bd 2桁以上のcdnのURLに対応できるように正規表現を修正 2019-09-09 10:58:20 +09:00
eai04191 d049a6f631 すべてwixmpを使用するようになったので分ける必要がなくなった
ついでに$data['thumbnail_url']なら常にオプションが付いているのでオプションを含んでいるか判別する必要がなくなった
2019-09-09 10:30:10 +09:00
eai04191 4add9a87cc Update Fixture 2019-09-09 10:20:39 +09:00
eai04191 c898487a20 Update Tests 2019-09-09 10:01:26 +09:00
eai04191 03cb2b0728 Update Toranoana Fixture 2019-09-09 09:59:08 +09:00
eai04191 3c0b65ff8c Update Tests 2019-09-09 09:47:42 +09:00
eai04191 b367009c5c Update DLsite Fixture 2019-09-09 09:35:38 +09:00
shibafu 22150d0e7a 同じオカズでチェックインする際にセンシティブフラグを継承する 2019-09-08 16:32:37 +09:00
MitarashiDango 2b98267fa8 設定項目のアイコン変更 2019-09-08 02:39:18 +09:00
MitarashiDango a7972046ef fix stylelint error 2019-09-07 21:19:31 +09:00
MitarashiDango 524d00d0ed オーバーレイのスタイルを修正 2019-09-07 21:06:06 +09:00
MitarashiDango 06cc18565e チェックインに対してセンシティブフラグを付与可能とする対応を実施 2019-09-07 19:57:44 +09:00
shibafu ff6de777d7
Merge pull request #268 from shikorism/develop
Release 20190906.0000
2019-09-06 00:06:31 +09:00
shibafu 743272f8d6
Merge pull request #266 from shikorism/feature/262-update-mail-address
メールアドレスを変更可能にする
2019-09-04 23:50:07 +09:00
shibafu 784fb43ae9
Merge pull request #267 from shikorism/package-update-20190904
Package update (20190904)
2019-09-04 23:49:50 +09:00
shibafu de23a37ab3 Update composer packages 2019-09-04 22:04:37 +09:00
shibafu 72fc84a42c Update npm packages 2019-09-04 21:56:35 +09:00
shibafu f59aa750e4
Merge pull request #265 from shikorism/dependabot/npm_and_yarn/mixin-deep-1.3.2
Bump mixin-deep from 1.3.1 to 1.3.2
2019-09-04 20:54:18 +09:00
shibafu 66f4c45f5c メールアドレスを変更可能にする 2019-09-04 20:52:26 +09:00
dependabot[bot] c204a7e934
Bump mixin-deep from 1.3.1 to 1.3.2
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-09-04 11:42:19 +00:00
shibafu aa87a8f070
Merge pull request #261 from eai04191/feature/resolver-dlsite-affiliate
DLsiteResolver アフィリエイトURLに対応
2019-09-01 18:05:16 +09:00
Aoi Irie ab20ca5370
Update app/MetadataResolver/MetadataResolver.php
マージをミスるって

マジ

Co-Authored-By: shibafu <shibafu528@gmail.com>
2019-09-01 16:55:37 +09:00
Aoi Irie bd84f29a27
Merge branch 'develop' into feature/resolver-dlsite-affiliate 2019-09-01 03:43:37 +09:00
shibafu ac2077af49
Merge pull request #259 from eai04191/feature/resolver-nijie
NijieResolver 修正など
2019-08-31 03:12:34 +09:00
shibafu 27970e3ac5
Merge pull request #260 from eai04191/feature/resolver-iwara-improve
IwaraResolver 拡張など
2019-08-31 03:12:17 +09:00
shibafu 4940b7a9ca
Merge pull request #252 from MitarashiDango/fix_tag_input_android
タグ入力確定時のフォールバック処理を追加
2019-08-29 00:18:07 +09:00
eai04191 5e02a8ab7a Iwara側のURL構造変更に追従 2019-08-29 00:01:17 +09:00
eai04191 a088444626 textの引数を指定して例外を回避する 2019-08-29 00:00:03 +09:00
eai04191 8ef9a1f8f4 Update fixture 2019-08-28 23:57:23 +09:00
eai04191 150a8152a4 指摘箇所の修正 2019-08-28 23:48:53 +09:00
shibafu 5ac1bae73f
Update README.md 2019-08-28 23:25:48 +09:00
Aoi Irie 1bec21f15f
Merge branch 'develop' into feature/resolver-dlsite-affiliate 2019-08-28 00:31:20 +09:00
shibafu 2c1976fd2b
Merge pull request #256 from eai04191/feature/fix-deviantart
DeviantArtResolverでoEmbed APIを使用するように変更
2019-08-27 21:52:35 +09:00
eai04191 13c3407a4e テストを更新 2019-08-27 21:40:48 +09:00
eai04191 91e6cea79a wixmpのURL変換の修正
常にjpgを使用する
1024pxの画像を使用する
q_が付いていない場合に対応
2019-08-27 21:36:44 +09:00
eai04191 ac40a411da クエリの前に追加するように修正 2019-08-27 20:49:04 +09:00
shibafu e2aa47151b
Merge pull request #255 from eai04191/feature/resolver-dlsite-striptags
DLsiteResolverのdescriptionをstrip_tagsに通す
2019-08-27 20:05:42 +09:00
eai04191 dd38f4e0eb アフィリエイト先が不正なURLのテストを追加 2019-08-27 00:27:37 +09:00
eai04191 17bc8cebbf アフィリエイトURLに対応 2019-08-26 23:33:52 +09:00
eai04191 4f23a9404b 名前変更 2019-08-22 07:47:42 +09:00
eai04191 b7eafd881f descriptionが存在しない場合に対応 2019-08-22 07:28:28 +09:00
eai04191 0a994884a0 作者名をタグに追加する 2019-08-22 05:24:25 +09:00
eai04191 9926cc3357 役に立たないタグを含めない 2019-08-22 05:17:23 +09:00
eai04191 5069f20b50 タグ対応, images対応, テスト更新, その他 2019-08-21 05:11:36 +09:00
eai04191 93387f1ff5 assertEquals撲滅委員会 2019-08-21 03:53:32 +09:00
eai04191 7baf51fc09 書き直し, タグ対応, テスト更新 2019-08-21 03:40:47 +09:00
shibafu 0e3878a808
Merge pull request #257 from eai04191/feature/test-pixiv--this-item-has-been-deleted--very-sad
PixivResolver 作品削除に伴うテスト差し替え
2019-08-20 22:19:15 +09:00
shibafu 4c0b245574 Merge branch 'feature/249-install-dom-crawlar' into develop 2019-08-20 20:52:57 +09:00
shibafu 0a0047c4c3 symfony/css-selector を依存関係に追加
refs #249
2019-08-20 20:52:12 +09:00
shibafu 831d1668ef
Merge pull request #258 from shikorism/feature/249-install-dom-crawlar
symfony/dom-crawler を依存関係に追加
2019-08-20 20:50:10 +09:00
shibafu 51c8199283 symfony/dom-crawler を依存関係に追加
refs #249
2019-08-20 20:46:28 +09:00
shibafu 78a1bdfb30
Merge pull request #254 from shikorism/feature/php-7.3
DockerfileおよびCI環境をPHP 7.3にアップデート
2019-08-20 20:44:39 +09:00
eai04191 ceff57f9f6 作品削除に伴いテスト差し替え 2019-08-20 11:31:50 +09:00
eai04191 bc2f8662fc oEmbed APIを使用するように変更 2019-08-20 11:14:44 +09:00
eai04191 2112087e89 nbspをspaceに置換 2019-08-20 01:40:02 +09:00
eai04191 c93ccb43c8 strip_tags追加 2019-08-20 00:52:00 +09:00
shibafu 58ae1bc1c1 DockerfileおよびCI環境をPHP 7.3にアップデート 2019-08-13 17:04:06 +09:00
shibafu f7c9e83b12
Merge pull request #251 from shikorism/schedule-ci
定期的に実際のリクエストを伴うMetadataResolverのテストを実行する
2019-08-10 12:36:31 +09:00
shibafu a1850b666b 定期テストではMetadataResolverのテストのみを実行する 2019-08-10 12:18:36 +09:00
MitarashiDango 8594caade1 タグ入力確定時のフォールバック処理を追加 2019-08-09 00:57:14 +09:00
shibafu dddb47f68a
Merge pull request #248 from eai04191/feature/unknown-territory
Add XtubeResolver
2019-08-08 00:26:17 +09:00
shibafu 1b2b043be2
Merge pull request #246 from shikorism/feature/monthly-graph-term
月間チェックイングラフの表示期間を選択可能にする
2019-08-08 00:23:15 +09:00
shibafu c535153e1f 定期的に実際のリクエストを伴うMetadataResolverのテストを実行する 2019-08-08 00:14:59 +09:00
eai04191 830de3a5e3 Add XtubeResolver 2019-08-06 22:44:38 +09:00
shibafu ab46117138 対象年の表記を yyyy年 にした 2019-08-04 01:33:54 +09:00
shibafu 3c2fec21a0 月間チェックイングラフの対象年を切り替えられるようにした 2019-08-04 01:31:53 +09:00
shibafu 370d1cc01b 月間グラフのデータ整形をクライアントサイドでやらせる 2019-08-04 00:57:35 +09:00
shibafu 5517cd5fab
Merge pull request #244 from shikorism/prestissimo
prestissimoのインストールをDockerfileに含める
2019-08-03 17:17:34 +09:00
shibafu 3c083a7c60
Merge pull request #243 from shikorism/fix/235-tora
ToranoanaResolverで、OGP画像の代わりになりそうなサムネ画像を取得する
2019-08-03 17:06:56 +09:00
shibafu fa6b8b87af READMEからprestissimoのインストールを削除 2019-08-03 01:00:15 +09:00
shibafu d290bf4107 prestissimoを予めインストールしておく 2019-08-03 00:59:53 +09:00
shibafu b274c6bc40 Cookieを付与しなくてもデータを取得できたので、付与しないように変更 2019-08-03 00:26:12 +09:00
shibafu 018532f01f ToranoanaResolverのテストを追加 2019-08-03 00:16:21 +09:00
shibafu e4ef935dd2 OGP画像が全て代替イメージになっていたため、サムネイルのスクレイピングを実施 2019-08-02 23:48:56 +09:00
shibafu dabae9f251
Merge pull request #242 from shikorism/develop
Release 20190725.2018
2019-07-25 20:19:19 +09:00
shibafu fb84a1d416
Merge pull request #241 from shikorism/dependabot/npm_and_yarn/lodash-4.17.15
Bump lodash from 4.17.11 to 4.17.15
2019-07-25 20:17:24 +09:00
dependabot[bot] 358580a15e
Bump lodash from 4.17.11 to 4.17.15
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-25 11:12:45 +00:00
shibafu 000b89f380
Merge pull request #237 from eai04191/feature/card-round-fix
カードの角丸を修正
2019-07-14 01:06:51 +09:00
shibafu c5cbad4475
Merge pull request #238 from shikorism/feature/disable-inserted-tag
入力済みのタグ候補の背景色を変更する
2019-07-14 01:06:02 +09:00
shibafu f4abb08921 編集モードの初期表示時に入力済みタグが反映されていなかったので、現在のタグを配信させるイベントを定義 2019-07-04 22:34:28 +09:00
shibafu 38eb0348f9 入力済みのタグ候補の背景色を変更する 2019-07-04 22:33:28 +09:00
eai04191 4f5595dae0 vue側も追従 2019-07-04 21:28:54 +09:00
eai04191 733e97bc58 card-img類削除、.cardにoverflow付与 2019-07-04 21:28:26 +09:00
shibafu c4768ded38 Revert "Merge pull request #138 from eai04191/feature/bootstrap-custom"
This reverts commit 077731495c.
2019-07-04 20:58:59 +09:00
eai04191 598d27f6b8 Revert "Merge pull request #153 from shikorism/fix/140"
This reverts commit d044b6db20.
2019-07-04 20:55:33 +09:00
shibafu cf5e269fd8
Merge pull request #233 from eai04191/feature/lint-tests
Lint tests
2019-07-02 12:51:40 +09:00
eai04191 4747f822ab Lint tests 2019-07-02 12:44:25 +09:00
shibafu bcf78df2fc
Merge pull request #228 from shikorism/develop
Release 20190629.1945
2019-06-29 19:50:51 +09:00
shibafu fa171bc3d3
Merge pull request #224 from shikorism/feature/105-tag-suggest
チェックイン時にメタデータからタグをサジェストする
2019-06-29 19:17:07 +09:00
shibafu b828a233bc
Merge pull request #227 from eai04191/feature/icon-identity
Gravatarのデフォルトアイコンをretroにする
2019-06-29 17:24:17 +09:00
shibafu bbfd6a9895
Merge pull request #226 from eai04191/feature/resolver-pixiv-fix
PixivResolverの取得画像をregularにする
2019-06-29 00:13:44 +09:00
shibafu e1dd2b1c8f メタデータの読み込み中・読み込み失敗を表示するようにした 2019-06-28 00:27:31 +09:00
shibafu ec4e0f3dda メタデータプレビュー専用のスタイルなので .link-card-mini はSFC内に封印 2019-06-27 23:55:36 +09:00
shibafu 0aed1d9ebe 画像を含まないメタデータの場合、サムネイルを非表示にする 2019-06-27 23:53:04 +09:00
shibafu d8cdf218b7
Update resources/assets/sass/components/_link-card.scss
Co-Authored-By: Aoi Irie <eai@mizle.net>
2019-06-27 23:50:59 +09:00
eai04191 7c9eefe478 Gravatarのデフォルトをretroに指定 2019-06-27 13:32:20 +09:00
eai04191 810a1dbc59 PixivResolverの取得画像をregularにする 2019-06-27 00:34:53 +09:00
shibafu a521a26aa5
Merge pull request #225 from eai04191/feature/test-komiflo
KomifloResolverのテストを追加
2019-06-27 00:21:24 +09:00
eai04191 e80acf79b7 KomifloResolverのテストを追加 2019-06-27 00:05:47 +09:00
shibafu 1b5fbfabc4
Merge pull request #223 from eai04191/feature/codecov
codecovを追加する
2019-06-26 23:32:11 +09:00
shibafu 0ad0b268bc 既に入力されているタグを二重追加しない 2019-06-26 23:23:06 +09:00
shibafu da19806a3d ページロード時点でオカズリンクにURLが入力されている場合、すぐにメタデータを取得する 2019-06-26 23:20:53 +09:00
eai04191 4390af53f9 revert Dockerfile 2019-06-26 23:15:04 +09:00
shibafu dd12582dba
Merge pull request #189 from eai04191/feature/test-pixiv
PixivResolverのテストを追加
2019-06-26 22:32:15 +09:00
eai04191 6e81f091d1 必要のないパイプを削除 2019-06-26 15:46:35 +09:00
eai04191 c60d41427d Add codecov 2019-06-26 15:31:14 +09:00
shibafu b8482e0e3c メタデータプレビューとタグ候補選択のコンポーネント 2019-06-26 01:44:18 +09:00
shibafu a1cb313d4f Card APIでタグ情報も取れるようにする 2019-06-26 01:40:55 +09:00
eai04191 53f7a17b8e PixivResolverのテストを追加 2019-06-26 01:12:25 +09:00
shibafu 41039a6650
Merge pull request #214 from shikorism/feature/editorconfig
.editorconfigを追加
2019-06-24 22:01:46 +09:00
shibafu 6d4f6e47a3
Merge pull request #222 from shikorism/fix/218
ユーザー入力テキストをLinkifyする時に target="_blank" rel="noopener" を付与する
2019-06-24 22:01:13 +09:00
shibafu 47eec65101 ユーザー入力テキストをLinkifyする時に target="_blank" rel="noopener" を付与する 2019-06-24 20:19:58 +09:00
shibafu c2da5eef9d
Merge pull request #217 from eai04191/feature/update-readme
README更新
2019-06-24 20:11:16 +09:00
shibafu 94cabdc827
Merge pull request #204 from shikorism/feature/average-range-limit
平均記録を直近30チェックインから算出するように変更
2019-06-24 20:10:20 +09:00
shibafu 1e11bd3290 JSON fileのインデント幅を指定
ただしcomposer.jsonは4 spaceを使うので、据え置く
2019-06-24 20:05:30 +09:00
shibafu f729fa7908 YAML fileのインデント幅を指定 2019-06-24 19:59:43 +09:00
shibafu cb1b2c9902
Merge pull request #206 from eai04191/feature/resolver-steam
SteamResolverを追加
2019-06-18 23:30:32 +09:00
shibafu 9a47bc970f
Merge pull request #216 from eai04191/feature/update-yarn-lock
update yarn.lock
2019-06-18 23:27:30 +09:00
shibafu 0c6cee6fcb
Merge pull request #215 from eai04191/feature/stylelint-ignore
.stylelintignoreを追加
2019-06-18 23:24:26 +09:00
eai04191 5172f1cb70 chownの変更先をstorageのみにする 2019-06-18 11:18:06 +09:00
eai04191 663888dcb1 prestissimoを使用してインストールを高速化 2019-06-18 11:16:51 +09:00
eai04191 762c232aef update yarn.lock 2019-06-18 11:14:11 +09:00
eai04191 e2332c7fe6 .stylelintignoreを追加 2019-06-17 07:10:08 +09:00
eai04191 16e5341de1 assertStringStartsWithに変更
モックを使わないテストがコケることがあるので
2019-06-17 04:29:54 +09:00
shibafu 8c5a7f4d09 .editorconfigを追加 2019-06-16 23:08:45 +09:00
shibafu fe09f769e3 テストを追加 2019-06-16 22:36:00 +09:00
shibafu 85012e13de Merge remote-tracking branch 'eai/feature/resolver-dlsite-regex' into develop
# Conflicts:
#	app/MetadataResolver/MetadataResolver.php
2019-06-16 19:46:51 +09:00
shibafu f19f970bd9
Merge pull request #212 from eai04191/feature/resolver-dlsite-fix-209
DLsiteResolverで予告作品に対応
2019-06-16 19:44:39 +09:00
shibafu d6127a7268
Merge pull request #211 from eai04191/feature/fix-210
composer fixでconfigを指定する
2019-06-16 19:43:51 +09:00
eai04191 073ed7e618 composer fixでconfigを指定する 2019-06-16 05:52:32 +09:00
eai04191 32c1d3ff9d 予告作品に対応 2019-06-16 05:50:22 +09:00
eai04191 ede45ee4e1 twitterリンクの正規表現を修正
howtw, cowtw, sowtw, maatw, bowtw, prwtw 等があるため
2019-06-16 05:24:33 +09:00
eai04191 fbecd97c03 いい加減push前にフォーマットする習慣をつけろ 2019-06-16 04:58:38 +09:00
eai04191 9306a4376c 200でもエラーの時があるのでsuccessも見るようにする
やり方これであってるのか?
2019-06-16 04:58:38 +09:00
eai04191 c061a51f8f SteamResolverを追加 2019-06-16 04:58:38 +09:00
shibafu b510ea4042
Merge pull request #205 from eai04191/feature/pixiv-api
PixivResolverの修正(2戦目)
2019-06-15 20:04:27 +09:00
shibafu e004a6bced
Merge pull request #208 from eai04191/feature/lint-staged-php
commit時にphp-cs-fixer fixするようにする
2019-06-15 18:57:05 +09:00
eai04191 b6864c6fc4 lint-stagedにphp-cs-fixerを追加する 2019-06-15 07:50:37 +09:00
eai04191 a45d5cd558 シリーズに対応
APIがわからないのでとりあえずOGPとcatだけ fix #172
2019-06-15 05:37:27 +09:00
eai04191 5f1a6291f7 pixivのajax APIを利用するように変更 2019-06-14 11:08:57 +09:00
shibafu ac91e36246
Merge pull request #203 from eai04191/feature/dlsite-tags
DLsiteResolverでタグを取得する
2019-06-13 00:35:49 +09:00
shibafu 709f10f098 平均記録を直近30チェックインから算出するように変更 2019-06-12 00:03:18 +09:00
eai04191 d1da60693a タグを取得するのとテストを追加 2019-06-08 01:55:26 +09:00
eai04191 b8f7e5e6ef update fixture 2019-06-08 01:46:50 +09:00
shibafu d926a9ea0d Test FixtureをGitHubの言語判定に含めないようにする 2019-06-08 01:16:33 +09:00
shibafu 65b0893f47
Merge pull request #199 from shikorism/feature/vue
タグ入力欄のVue化
2019-06-08 01:12:41 +09:00
shibafu b2301444c4
Merge pull request #202 from shikorism/fix/200
iOS対策 カード省略グラデーションの透明色指定をtransparentからrgba()に変更
2019-06-07 23:12:00 +09:00
shibafu e5e0ce08da iOS対策で、透明色の指定をtransparentからrgbaで透明な白に変更 2019-06-07 22:10:32 +09:00
shibafu 17ce2784a7
Merge pull request #187 from eai04191/fix/186
DLsiteResolverにてmakerに一致するテキストを探すように修正
2019-06-07 22:03:29 +09:00
shibafu d470193662
Merge pull request #201 from shikorism/dependabot/npm_and_yarn/js-yaml-3.13.1
Bump js-yaml from 3.12.1 to 3.13.1
2019-06-07 01:45:59 +09:00
dependabot[bot] ea93cc68fa
Bump js-yaml from 3.12.1 to 3.13.1
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.1 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.1...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 16:42:37 +00:00
shibafu 12dac5916e
Merge pull request #177 from shikorism/feature/137-card-max-height
サムネイルを含むカードを高さ400pxに固定し、トリミング表示されるように変更
2019-06-07 01:41:53 +09:00
shibafu f47d3454f6
Merge pull request #188 from eai04191/feature/env-mock
.env.exampleにTEST_USE_HTTP_MOCKを追加
2019-06-07 01:26:45 +09:00
shibafu 34cb3a1415 is-invalid classのこと忘れてた 2019-06-05 00:50:47 +09:00
shibafu 9471683741 タグ用のhidden inputもComponent内に含めるようにした 2019-06-05 00:46:30 +09:00
shibafu c7d88076fa インラインスタイルをスコープCSSに追い出した 2019-06-05 00:36:41 +09:00
shibafu 0670cb8736 タグ入力欄だけVue化 2019-06-05 00:06:30 +09:00
shibafu 7a95e0979e TypeScriptの音ォ〜! 2019-06-05 00:06:29 +09:00
shibafu 333f39c9f4 Vue.jsを依存関係に追加 2019-06-05 00:06:20 +09:00
shibafu 5340d8ead9
Merge pull request #194 from shikorism/dependabot/npm_and_yarn/webpack-bundle-analyzer-3.3.2
Bump webpack-bundle-analyzer from 3.1.0 to 3.3.2
2019-06-01 01:07:55 +09:00
dependabot[bot] 348096ecee
Bump webpack-bundle-analyzer from 3.1.0 to 3.3.2
Bumps [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) from 3.1.0 to 3.3.2.
- [Release notes](https://github.com/webpack-contrib/webpack-bundle-analyzer/releases)
- [Changelog](https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/webpack-bundle-analyzer/compare/v3.1.0...v3.3.2)
2019-05-31 15:47:46 +00:00
shibafu 35cc0c6357
Merge pull request #193 from shikorism/fix/pixiv-resolver-tag-filter
PixivResolverのタグ抽出がおそらく「R-18」を無視できていないのを修正
2019-06-01 00:42:48 +09:00
shibafu f0cb07c6f5
おそらく「R-18」を無視できていないのを修正 2019-05-30 23:24:33 +09:00
shibafu 3f9de593d6
Merge pull request #192 from shikorism/develop
Release 20190530.2249
2019-05-30 22:51:59 +09:00
eai04191 11ddb83424 テストの変更漏れを修正 2019-05-03 11:58:31 +09:00
eai04191 02367646a1 makerをOGPタイトルに含まれる著者名などから取得するように変更 2019-05-03 11:58:31 +09:00
eai04191 241bcd6548 テストをたくさん追加 2019-05-03 11:58:31 +09:00
eai04191 f7c8a3010d []を含むタイトルに対応 2019-05-03 11:58:31 +09:00
eai04191 c6a32da97e girlsに対応 2019-05-03 11:58:31 +09:00
eai04191 50ff2efaaa テストを修正 2019-05-03 11:58:31 +09:00
eai04191 a958ccaa08 makerに一致するテキストを探すように修正 2019-05-03 11:58:31 +09:00
shibafu ce3ef3cdff
Merge pull request #190 from eai04191/fix/164
DLsiteResolverの正規表現を修正
2019-05-03 11:05:22 +09:00
shibafu f9ea9cc566
Merge pull request #191 from shikorism/update/jquery-3.4.1
jQuery 3.4.1にアップデート
2019-05-03 11:00:11 +09:00
shibafu debc350b12
Merge pull request #185 from shikorism/feature/metadata_tag
MetadataResolverからタグ情報を保存できるようにする
2019-05-03 11:00:01 +09:00
shibafu d7f39fcc5a jQuery 3.4.1にアップデート 2019-05-03 10:25:05 +09:00
eai04191 8e6b96fb83 正規表現を修正 2019-05-03 09:36:59 +09:00
eai04191 c20bd0ca77 .env.exampleにTEST_USE_HTTP_MOCKを追加 2019-05-03 02:14:58 +09:00
shibafu c1330ff6e3 PixivResolver: meta[name=keywords] からタグっぽい情報を抽出して保存 2019-04-29 16:06:40 +09:00
shibafu 085afd3318 KomifloResolver: 作者情報と作品タグをタグとして保存 2019-04-29 14:51:53 +09:00
shibafu a8a6aecef3
Merge pull request #184 from MitarashiDango/fix_ime_conversion
特定条件下においてタグ入力が正常に行えない問題の修正
2019-04-29 14:32:54 +09:00
shibafu e4c942263a MetadataResolverからタグ情報を保存できるようにした 2019-04-29 12:43:05 +09:00
shibafu 1322e89b86 Metadata - Tags の多対多リレーション追加 2019-04-29 11:40:17 +09:00
MitarashiDango dbafe2c75e 特定条件下においてタグ入力が正常に行えない問題の修正 2019-04-25 03:11:11 +09:00
shibafu 2efb387b6a
Merge pull request #183 from shikorism/develop
Release 20190421.1742
2019-04-21 17:44:01 +09:00
shibafu 91c786199a アナル締めた 2019-04-21 17:12:18 +09:00
shibafu ed295cb7bc
Merge pull request #182 from shikorism/develop
Release 20190421.0218
2019-04-21 02:18:44 +09:00
shibafu 8de5fa891e
Merge pull request #181 from shikorism/fix/private-like
非公開チェックインに対するいいね関係のバグ修正
2019-04-21 02:16:47 +09:00
shibafu 464b690fbd 非公開チェックインのいいねに「非公開」の表記がなかったので付けた 2019-04-21 02:14:08 +09:00
shibafu d02b65e4ed 非公開チェックインのいいねが他人に見えてしまっていた不具合の修正 2019-04-21 02:12:42 +09:00
shibafu 0c18965ade
Merge pull request #180 from shikorism/develop
Release 20190421.0114
2019-04-21 01:23:03 +09:00
shibafu 51485a8ac1
Merge pull request #179 from shikorism/fix/178-tora-url
ToranoanaResolverのマッチ対象に電子書籍と女性向け通販を追加
2019-04-20 23:49:34 +09:00
shibafu 59a6aa869f ToranoanaResolverのマッチ対象に電子書籍と女性向け通販を追加 2019-04-20 22:38:36 +09:00
shibafu b3ea665f0b
Merge pull request #176 from shikorism/fix/174-ap-empty-content
ActivityPubResolverでcontentが空のときはHTMLとしてのパースを行わないようにする
2019-04-17 23:38:52 +09:00
shibafu f791fd8fbd
Merge pull request #160 from eai04191/feature/readme-phpunit
READMEに phpunit の使い方を追記
2019-04-17 23:38:23 +09:00
shibafu 676793cfe5
Merge pull request #173 from shikorism/koresuki
チェックインに対する「いいね」機能
2019-04-17 19:55:42 +09:00
shibafu 2ff07cc68d サムネイルを含むカードを高さ400pxに固定、サムネイルはトリミング表示されるようにした 2019-04-14 23:16:05 +09:00
shibafu f95f1592f7 contentが空のときはHTMLとしてのパースを行わないようにする 2019-04-14 17:40:31 +09:00
shibafu d655f24fbf コメントの手直し 2019-04-14 16:47:58 +09:00
shibafu b80d74bae1 いいねしたユーザーの表示を直近10ユーザーのみに絞りこむ 2019-04-14 16:46:20 +09:00
shibafu 9b95f3a8b8 eloquent-eager-limit を依存関係に追加 2019-04-14 16:39:14 +09:00
shibafu 859a186acb 詳細画面ではいいねユーザーのアイコンを少し大きく表示 2019-04-14 02:18:38 +09:00
shibafu fca6b6e98b いいねユーザー表示の文字部分の幅が縮まないようにした 2019-04-14 02:16:33 +09:00
shibafu 26b52e1c87
Merge pull request #175 from eai04191/feature/icon-preview-in-setting
プロフィール設定にアイコンプレビューと登録メールアドレスの欄を追加する
2019-04-13 22:18:43 +09:00
eai04191 f895996b18 phpunit の使い方を追記 2019-04-13 18:36:21 +09:00
eai04191 f19621c04a プロフィール設定に登録メールアドレスを表示 2019-04-13 18:21:21 +09:00
eai04191 e8cfc48417 プロフィール設定にアイコンプレビューとGravatarへのリンクを追加 2019-04-13 18:20:12 +09:00
shibafu 566d288395 いいねタブが常に表示されるように変更 2019-04-09 23:09:59 +09:00
shibafu ddac533539 いいね一覧の公開設定を追加 2019-04-09 23:09:59 +09:00
shibafu c20a8066c9 生クエリ/// 2019-04-09 23:09:59 +09:00
shibafu 664448b9fc いいね秘匿用のフラグ users.private_likes の追加 2019-04-09 23:09:59 +09:00
shibafu e9c1726567 いいねユーザー表示の項目表示をアイコンから文字列に変更 2019-04-07 23:44:03 +09:00
shibafu db7dce5830 Scssファイル分割 2019-04-07 23:30:03 +09:00
shibafu 4ed2a9048d いいねしたユーザーの一覧を表示 2019-04-07 23:27:24 +09:00
shibafu 2cd09402d1 チェックインに対する操作ボタンの位置を変更 2019-04-07 22:50:03 +09:00
shibafu 6b1ccc52e5
Merge pull request #171 from shikorism/develop
Release 20190407.0014
2019-04-07 00:15:38 +09:00
shibafu 3cba46bff0
Merge pull request #170 from shikorism/fix/visibility-issue-on-search
チェックイン非公開ユーザーのチェックインが検索結果として表示される問題の修正
2019-04-07 00:13:16 +09:00
shibafu 9cec184d21 チェックイン非公開ユーザーのチェックインが検索結果として表示される問題の修正 2019-04-07 00:10:01 +09:00
shibafu 1b4f621191 fix style 2019-04-06 00:28:44 +09:00
shibafu 5bafe9126a ヘッダーメニューにいいね一覧へのリンクを追加 2019-04-06 00:15:54 +09:00
shibafu fe880ee599 いいね一覧の追加 2019-04-06 00:14:05 +09:00
shibafu a15716bb54
Merge pull request #167 from eai04191/develop
画像の最適化
2019-04-05 23:22:26 +09:00
shibafu 02f03165d6 ボタン部分のスマートフォンにおける表示を改善 2019-04-05 23:11:33 +09:00
shibafu 225d0854ef いいねボタンの追加 2019-04-05 23:11:20 +09:00
shibafu 34b7cd6c89 Like APIの追加 2019-04-05 23:10:44 +09:00
Eai 199e5dac05
Merge pull request #14 from eai04191/imgbot
[ImgBot] Optimize images
2019-04-02 03:12:58 +09:00
ImgBotApp 062034fb83
[ImgBot] Optimize images
*Total -- 14.84kb -> 11.65kb (21.49%)

/public/chrome-touch-icon-192x192.png -- 7.71kb -> 6.05kb (21.58%)
/public/apple-touch-icon.png -- 7.12kb -> 5.60kb (21.4%)
2019-04-01 16:43:37 +00:00
shibafu 212fad4d66
Merge pull request #166 from shikorism/fix/exclude-future-checkin-from-stats
グラフ画面で表示するデータ範囲を当月末までに制限
2019-03-31 09:55:40 +09:00
shibafu 04d7116eca
Merge pull request #163 from shikorism/fix/128-bdi-name
チェックインビュー上のdisplay_nameをbdiタグでマークアップ
2019-03-31 09:52:28 +09:00
shibafu cc8ee2e520 グラフ画面で表示するデータ範囲を当月末までに制限 2019-03-31 09:46:28 +09:00
shibafu 04f1a344a0 チェックインビュー上のdisplay_nameをbdiタグでマークアップ 2019-03-26 22:25:39 +09:00
shibafu 379d4563c5
Merge pull request #162 from unarist/theme-color
manifest.jsonにテーマカラーを追加
2019-03-26 22:16:22 +09:00
unarist ca2aeea4f5 manifest.jsonにテーマカラーを追加 2019-03-22 00:29:52 +09:00
shibafu 5153de54d2
Merge pull request #161 from shikorism/develop
Release 20190321.1905
2019-03-21 19:08:56 +09:00
shibafu 0e45d27295
Merge pull request #147 from eai04191/feature/theme-color
プライマリカラーを変更
2019-03-19 22:52:14 +09:00
shibafu 8e161252a7
Merge pull request #158 from shikorism/feature/xdebug-for-linux
Linux+Dockerな開発環境でxdebugが使えるようにコールバック先IPアドレスの設定を調整
2019-03-19 22:45:43 +09:00
shibafu a7859fdda6 set -eしてるんだから落ちるだろうが 2019-03-19 00:56:31 +09:00
shibafu 34df704fdb host.docker.internalが使える場合は使う 2019-03-19 00:35:23 +09:00
shibafu 80fe53cf20 Linux+Dockerな開発環境でxdebugが使えるように、コールバック先IPアドレスの設定を調整 2019-03-18 23:22:28 +09:00
shibafu b8ceac51f7
Merge pull request #156 from shikorism/feature/admin
お知らせ管理機能 (+ 管理者用画面)
2019-03-17 20:14:41 +09:00
shibafu 14b57bf9f5 fix DLsiteResolver test
refs #132
2019-03-17 20:07:44 +09:00
shibafu 40fdb587d7
Merge pull request #132 from eai04191/feature/resolver-dlsite-format
DLsiteResolverで余分な説明文を削除・整形する
2019-03-17 20:04:18 +09:00
shibafu 1fd43b5e38 お知らせ登録・編集のバリデーションエラー表示 2019-03-16 12:29:33 +09:00
shibafu a998d7132f バリデーションをFormRequestで行う 2019-03-16 12:22:07 +09:00
shibafu 74c8a1b6cb 改行コードの正規化を削除 2019-03-16 10:45:51 +09:00
shibafu e6b333eea4 Merge remote-tracking branch 'origin/feature/normalize-line-ending' into feature/admin 2019-03-16 10:45:02 +09:00
shibafu 285e529aea
Merge pull request #134 from eai04191/feature/resolver-melonbooks-format
MelonbooksResolverで余分な説明文を削除・整形する
2019-03-16 10:44:13 +09:00
shibafu a72190eda5
Merge pull request #154 from shikorism/feature/normalize-line-ending
改行コードを正規化する処理をミドルウェア化
2019-03-16 09:51:21 +09:00
shibafu ea2db88de3
Merge pull request #155 from hinaloe/feature/webpack-docker
Dockerにnodeを追加する
2019-03-16 09:51:11 +09:00
eai04191 54477bb214 余分な文の削除・整形 2019-03-16 05:36:49 +09:00
hina 176ccef20f
mix周りのREADME草案 2019-03-14 21:21:31 +09:00
hina dd4837ef7b
とりあえずDockerfileにnodeを追加 2019-03-14 20:45:01 +09:00
shibafu 9e786a5469 テストを追加 2019-03-14 00:59:19 +09:00
shibafu df3826a6d4 コントローラ内で実装されていた改行コードの正規化を削除 2019-03-14 00:47:52 +09:00
shibafu a35b58eb47 改行コードを正規化する処理をミドルウェア化 2019-03-14 00:43:31 +09:00
shibafu 27fc5ee6e8 fix style 2019-03-14 00:10:09 +09:00
shibafu be700ab81b お知らせ登録・編集・削除を実装 2019-03-14 00:10:09 +09:00
shibafu 53ac4c9b8f お知らせ編集画面の表示のみ実装 2019-03-14 00:10:09 +09:00
shibafu e69adbfbc3 ダッシュボード画面の追加 2019-03-14 00:10:09 +09:00
shibafu f5fab4b3c1 管理者権限ゲートの定義 2019-03-14 00:10:08 +09:00
shibafu 82ccd623a6 管理者昇格/降格 CLIコマンド 2019-03-14 00:10:08 +09:00
shibafu e98ed0c3ca users.is_admin 列の追加 2019-03-13 23:25:39 +09:00
shibafu 2dd5cbd072
Merge pull request #149 from eai04191/feature/resolver-fc2contents
FC2ContentsResolverを追加
2019-03-13 22:57:45 +09:00
shibafu d044b6db20
Merge pull request #153 from shikorism/fix/140
カード画像の角丸の位置をメディアクエリで可変にした
2019-03-13 20:40:31 +09:00
shibafu 8e366870b1 カード画像の角丸の位置をメディアクエリで可変にした 2019-03-12 20:44:26 +09:00
shibafu 54eec1a861
Merge pull request #152 from shikorism/fix/151
タグ検索結果から編集・削除ボタンを消す
2019-03-12 20:35:16 +09:00
shibafu 8a39feff29 タグ検索結果から編集・削除ボタンを消す
fix #151
2019-03-12 20:32:47 +09:00
shibafu 8a8ca1a26e
Merge pull request #148 from shikorism/fix/145-show-delete-modal-manually
削除モーダルの初期化が完了してから削除ボタンクリックイベントを仕掛ける
2019-03-12 19:48:05 +09:00
shibafu e262b27d0d
Merge pull request #150 from eai04191/feature/remove-time-bomb
アラートの自動削除を削除
2019-03-12 19:47:49 +09:00
eai04191 bd1976c4cf アラートの自動削除を削除
close #146
2019-03-12 03:44:35 +09:00
eai04191 3fa2d80507 Fix style 2019-03-12 03:38:05 +09:00
eai04191 ec5a78db38 FC2ContentsResolverのテストを追加 2019-03-12 03:31:16 +09:00
eai04191 2db45951f4 FC2ContentsResolverを追加 2019-03-12 03:30:48 +09:00
shibafu 00a819de23 削除モーダルの初期化が完了してから削除ボタンクリックイベントを仕掛ける 2019-03-11 22:55:32 +09:00
eai04191 4f559cd1d4 プライマリカラーを変更 2019-03-11 21:26:34 +09:00
shibafu 16005931fc fix style 2019-03-10 21:49:23 +09:00
shibafu a58811a8fe
Merge pull request #144 from shikorism/fix/stylelint-args
stylelintの対象ファイルパターンを修正
2019-03-10 21:46:59 +09:00
shibafu 89c0b39755 stylelintの対象ファイルパターンを修正 2019-03-10 21:38:50 +09:00
shibafu 1fb4352e48 Merge branch 'feature/stylelint' into develop 2019-03-10 20:44:23 +09:00
shibafu ad747577e4 fix style 2019-03-10 20:43:38 +09:00
eai04191 a2ee4ef505 huskyとlint-stagedを追加してコミット前にcssをlintする 2019-03-10 20:00:58 +09:00
eai04191 5d1ffca1ee CircleCIにstylelintによるlintを追加 2019-03-10 20:00:41 +09:00
shibafu 5c612d7eef
Merge pull request #118 from eai04191/feature/plurk
PlurkResolverを追加
2019-03-10 18:52:58 +09:00
shibafu cf0d370e61 fix style 2019-03-10 18:52:03 +09:00
shibafu 91ec1c391e
Merge pull request #141 from eai04191/feature/bootstrap-4.3.0
Bootstrap 4.3.1にアップデート
2019-03-10 18:33:36 +09:00
eai04191 83d0fb3a7a npm scriptを追加
npm run stylelintで実行可能
2019-03-10 18:22:16 +09:00
eai04191 b8f7b5dfe0 stylelint-config-recess-orderを導入 2019-03-10 18:21:15 +09:00
eai04191 51fc65e66f Stylelintを導入 2019-03-10 18:10:20 +09:00
eai04191 a674195db9 もっと見るリンクをStretched linkにする
リンク範囲が広いとうれしい
2019-03-10 17:58:29 +09:00
shibafu 1a7b6c8f3c
Merge pull request #142 from eai04191/feature/gitignore-vscode
/.vscodeを.gitignoreに追加
2019-03-10 17:35:09 +09:00
shibafu 077731495c
Merge pull request #138 from eai04191/feature/bootstrap-custom
Bootstrapのカスタムcssを別のファイルに移動する
2019-03-10 17:33:29 +09:00
eai04191 7190367936 /.vscodeを.gitignoreに追加 2019-03-10 16:41:22 +09:00
eai04191 e1eb359887 .tis-word-wrapを廃止して.text-breakを使用する 2019-03-10 16:28:38 +09:00
eai04191 57b10d98ac Bootstrap 4.3.1にアップデート 2019-03-10 16:16:47 +09:00
eai04191 7c70e6db7e typo修正 2019-03-10 15:41:34 +09:00
eai04191 b430ba7162 partialにする 2019-03-10 15:36:55 +09:00
shibafu d9d6c10a34
Merge pull request #136 from shikorism/fix/87-meta-desc-line-break
メタデータのdescriptionに含まれる改行を表示に反映する
2019-03-10 15:36:08 +09:00
shibafu 1a7d958a1e Sass入ってるのに生CSSで書こうとしたやつがいるらしい 2019-03-09 17:07:00 +09:00
eai04191 e983a3da0b border-radiusのmixinを使用する 2019-03-09 03:49:47 +09:00
eai04191 ed1cfe94f0 Bootstrapのカスタムを別のファイルに移動する 2019-03-09 03:42:45 +09:00
shibafu cd56e1bff3 メタデータのdescriptionに含まれる改行を表示に反映する
refs #87
2019-03-09 01:34:58 +09:00
shibafu 5db60a4524
Merge pull request #133 from hinaloe/feature/extract-vendorjs
複数のエントリポイントから共通して利用されているベンダモジュールを外出し
2019-03-08 23:20:59 +09:00
shibafu 3f0171fa8b
Merge pull request #131 from eai04191/feature/resolver-fanza-tag-fix
FanzaResolverでdescriptionにある不要な`<>`を削除する
2019-03-08 23:05:13 +09:00
shibafu 61498133d5 fix style 2019-03-08 23:02:24 +09:00
shibafu 088901fec7
Merge pull request #129 from eai04191/feature/dlsite-resolver-shortlink
DLsiteResolverをdlsite.jpの形式に対応させる
2019-03-08 22:58:53 +09:00
shibafu dab1732a1d
Merge pull request #127 from eai04191/feature/patreon-esolver-fix
PatreonResolverにてtoken-timeがある場合のみexpires_atを指定するように変更
2019-03-08 22:54:10 +09:00
shibafu 0b87a35fba fix style 2019-03-08 22:52:42 +09:00
hina 5561f0785c
中途半端に重複してたのをまとめる 2019-03-08 08:49:29 +09:00
hina 1ba7df6e82
versioning script 2019-03-08 06:54:13 +09:00
hina 94c19235b6
複数のエントリポイントから共通して利用されているベンダモジュールを外出し 2019-03-08 06:53:13 +09:00
hina e8438a78a1
Add bundle analyzer 2019-03-08 06:52:29 +09:00
eai04191 da0fc3f3bf テストを修正 2019-03-08 06:29:33 +09:00
eai04191 d561ee66c2 trim追加 2019-03-08 06:29:16 +09:00
eai04191 d571ff1a5b 余分な文を削除・整形する 2019-03-08 06:21:33 +09:00
eai04191 a2f0beb3cb descriptionにある不要な`<>`を削除する 2019-03-08 05:31:01 +09:00
eai04191 41778844b8 dlsite.jpの形式に対応 2019-03-08 05:12:03 +09:00
eai04191 b29bb23b40 PlurkResolverのテストを追加 2019-03-08 03:58:45 +09:00
eai04191 a364de7d03 token-timeがある場合のみexpires_atを指定するように変更 2019-03-08 03:41:04 +09:00
shibafu 03fcc424d8
Merge pull request #126 from shikorism/develop
Release 20190307.2250
2019-03-07 22:51:27 +09:00
shibafu ddd2a05607
Merge pull request #125 from shikorism/feature/mix
Laravel Mix
2019-03-05 22:07:36 +09:00
shibafu f25312a987 テスト前にmixのビルドを行う 2019-03-05 20:34:08 +09:00
shibafu f7d9c5c1e6 にゃーん 2019-03-05 20:25:06 +09:00
shibafu 2e1ec0dfc7 Remove comment 2019-03-05 01:27:37 +09:00
shibafu f1c56bce83 チェックイン登録/編集画面のインラインスクリプトをcheckin.jsに移動 2019-03-05 01:26:17 +09:00
shibafu 0ceb0fcf21 チェックイン削除モーダルのセットアップは共通処理に吸収 2019-03-05 01:23:14 +09:00
shibafu 37eaefc016 プライバシー設定画面のインラインスクリプトをsetting/privacy.jsに移動
これjQuery依存なくしてインラインのままでも良いような...
2019-03-05 01:17:49 +09:00
shibafu db09bf40a6 整理しやすくするため、$.linkCardの呼出を削除 2019-03-05 01:15:00 +09:00
shibafu 1348054858 グラフ画面のデータ参照を少しだけマシにした 2019-03-05 01:11:42 +09:00
shibafu 2c396da84e グラフ画面のインラインスクリプトをuser/stats.jsに移動 2019-03-05 01:11:42 +09:00
shibafu d4d98db686 ホーム画面のインラインスクリプトをhome.jsに移動 2019-03-05 01:11:42 +09:00
shibafu 81e37034ce ベーステンプレートのインラインスクリプトをapp.jsに移動 2019-03-05 01:11:41 +09:00
shibafu 8cdf086296 /public に直接コミットされていたファイルを削除 2019-03-05 01:11:41 +09:00
shibafu 7f087bf446 ベーステンプレートのアセット参照を貼り替え 2019-03-05 01:11:41 +09:00
shibafu 6a1848e311 既存のファイル化されているフロントコードを全てassetsに移動し、mixビルドの準備 2019-03-05 01:11:41 +09:00
shibafu 70f007b6d2 npmの依存関係を整理 2019-03-05 01:11:41 +09:00
shibafu b7701f39dd Laravel Mix v4.0系に更新 2019-03-05 01:11:41 +09:00
shibafu 7a421d648d
Merge pull request #124 from shikorism/feature/public-timeline
お惣菜コーナーをもっとたくさん見る画面
2019-03-05 01:09:15 +09:00
shibafu 8852c6b45b お惣菜コーナーの派生なので削除・修正ボタンは置かない 2019-03-04 23:21:04 +09:00
shibafu cf5bf2b274 お惣菜コーナーをもっとたくさん見る画面 2019-03-04 23:00:15 +09:00
shibafu e925a964f1
Merge pull request #119 from eai04191/test/DLsiteResolver
DLsiteResolverのテストを追加
2019-03-04 20:32:41 +09:00
shibafu e966995dea fix style 2019-03-03 00:29:43 +09:00
shibafu f21e58650d
Merge pull request #122 from shikorism/feature/circleci
CircleCIの設定ファイルを追加
2019-03-03 00:26:43 +09:00
shibafu 70fed1ddf0
Merge pull request #103 from unarist/feat/web-share-target
Web Share Target 実装(のためにPWA対応)
2019-03-02 22:00:29 +09:00
unarist c229947080 Web Share Target 実装(のためにPWA対応) 2019-03-02 20:00:52 +09:00
shibafu 08432c847e Add CircleCI Config 2019-03-02 18:55:04 +09:00
shibafu b961956b63
Merge pull request #117 from eai04191/feature/card-horizontal
カードのレイアウトを横向きに
2019-03-02 16:04:00 +09:00
shibafu 023857f7d7
Merge pull request #121 from shikorism/feature/favicon
faviconを作った
2019-03-02 15:56:51 +09:00
shibafu 5276e8d452 16x icoを書き起こす元気はないが、縮小したやつの質が悪いので消した 2019-03-02 14:52:58 +09:00
shibafu 3cba54946a faviconを作った 2019-03-02 14:24:43 +09:00
shibafu e6fe522f6d
laravel/laravel:5.5からTrustProxiesを輸入 (#120) 2019-03-02 11:06:08 +09:00
eai04191 7eeb0207de DLsiteResolverのテストを追加 2019-03-01 14:17:01 +09:00
eai04191 1beb411050 PlurkResolverを追加 2019-03-01 03:49:01 +09:00
shibafu eb97f01c79
Merge pull request #113 from hinaloe/fix/issue-110
コンテナ使っていないコンストラクタが残ってた fix #110
2019-03-01 00:13:50 +09:00
eai04191 0ff253cbfb cardのレイアウトを横向きに 2019-02-28 00:00:23 +09:00
shibafu 579bd3e31f
Merge pull request #108 from eai04191/feature/better-mobile-navbar
モバイルのナビメニューを整える
2019-02-27 23:46:22 +09:00
shibafu c80bb69568
Merge pull request #114 from eai04191/feature/card-component
リンクカードをコンポーネント化
2019-02-27 23:22:27 +09:00
eai04191 3c6dfeec1c cardコンポーネントの名前をlink-cardに変更 2019-02-27 22:52:45 +09:00
Eai 30c861d18c t.komiflo.comを利用したサムネイルの取得を追加 (#106) 2019-02-26 22:55:55 +09:00
Hinaloe 746db0474a add mailcatcher (#112) 2019-02-26 22:50:47 +09:00
Hinaloe 307e578d4a ルーターにコールバックで直接登録されてるルートをコントローラーに移動 (#111) 2019-02-26 22:46:40 +09:00
shibafu be6151f0c7 SP表示のアカウントメニューが画面外に突き抜けないようにした 2019-02-26 22:32:32 +09:00
shibafu c9cdd26728 非ログイン時にはアカウントメニューを出力しない
ログイン情報がないのに参照してコケていた
2019-02-26 22:26:22 +09:00
Eai d0dd2db159 概況の通算回数をnumber_formatでフォーマット (#115) 2019-02-26 21:59:47 +09:00
Eai ea12f8c9a6 typoを修正 (#109) 2019-02-26 21:51:17 +09:00
eai04191 dc98334a6d cardをコンポーネント化 2019-02-23 22:29:53 +09:00
hina a14b49b7d2
コンテナ使っていないコンストラクタが残ってた fix #110 2019-02-23 16:56:13 +09:00
eai04191 de740082b7 不要な.form-inlineで幅が制限されていたのを修正 2019-02-23 06:40:37 +09:00
eai04191 af964ad82f モバイルのナビメニューを整える
#107

Preview:

https://stellaria.network/system/media_attachments/files/000/070/479/original/0991a41baca49811.png
https://stellaria.network/system/media_attachments/files/000/070/527/original/4ace1b1df83bc380.png
2019-02-23 05:29:45 +09:00
shibafu 32b0b76032
Merge pull request #104 from hinaloe/test/fix-crlf
テスト用ファイルの改行コードなおした
2019-02-18 20:14:31 +09:00
hina db3ba04091
立つ鳥跡を濁さず
モックを使用しない場合のsleepを復活

close #102
2019-02-18 17:33:52 +09:00
hina 0400bc771c
gitに改行コード変えられてた 2019-02-18 17:32:09 +09:00
shibafu a5b4eeee36
Merge pull request #99 from shikorism/fix/68-paginator
ページャーの改善
2019-02-17 20:41:46 +09:00
shibafu f760ea7093
Merge pull request #101 from hinaloe/tests/mockable-resolver
GuzzleHttpをモック可能にする
2019-02-17 19:36:56 +09:00
shibafu 0f4dfcd816 全ページ数にはレイアウト調整犠牲になってもらう
* .page-linkと同様にline-heightを設定
* 高さ調整のためにheightを設定
2019-02-17 11:13:12 +09:00
hina a934a7fc35
リモートURLをリクエストするテストをトグれるモックに差し替える 2019-02-17 03:19:27 +09:00
hina 51f097fdf0
最初にやったニジエに抜けがあった 2019-02-17 03:18:59 +09:00
hina 24dee801ad
Guzzle\Clientをモッカブルにする 2019-02-17 02:58:36 +09:00
hina 9f1cd607d7
ignore ide-helper files 2019-02-17 02:51:52 +09:00
hina 4196b1a02d
Add `barryvdh/laravel-ide-helper` 2019-02-17 02:51:27 +09:00
Eai 35789befc5 pageが反映されていない問題を修正 (#98) 2019-02-17 00:24:25 +09:00
shibafu 32139cb9da ページネーションの自前HTMLを排除 2019-02-16 23:26:09 +09:00
shibafu 9244b8424d 最終ページを出してみる 2019-02-16 23:06:58 +09:00
shibafu 55eb95dda8 スマホ向けページャーでページジャンプを可能にした 2019-02-16 23:03:21 +09:00
shibafu 72e9d4e3e8 スマートフォン向けの簡易なページャーを用意 2019-02-16 23:03:19 +09:00
shibafu 852f1ac88c Bootstrap4用のページネーションテンプレートをpublish 2019-02-16 20:08:28 +09:00
shibafu f09ae32b00
Merge pull request #97 from shikorism/develop
Release 20190216.0130
2019-02-16 01:31:41 +09:00
shibafu 33be0ac8ef
CienResolverを追加 (#95) 2019-02-16 00:06:51 +09:00
shibafu 9f2e73e511
トップページに表示されるグラフが少なすぎるバグの修正 (#94) 2019-02-12 23:46:20 +09:00
shibafu e36b9c7c1b
Merge pull request #93 from shikorism/develop
Release 20190212.2300
2019-02-12 23:01:33 +09:00
shibafu 09bb98876c
Merge pull request #80 from shikorism/feature/noscript-info
ブラウザ設定でJavaScriptが無効になっている場合、メッセージを表示
2019-02-12 22:55:45 +09:00
Eai cedee0a20e pixivのOGP画像で常にプロキシURLを使用する (#92) 2019-02-12 22:48:44 +09:00
unarist 116dd3b798 OGPResolverでmeta[name="description"] にフォールバックする🐯 (#91) 2019-02-12 22:45:51 +09:00
unarist 735bb00eba 著作権表示の年を更新 (#90) 2019-02-11 23:44:07 +09:00
shibafu decb1707f1 PHP 7.0はオワコン 2019-02-11 13:18:27 +09:00
shibafu bec7bdeb36
Merge pull request #89 from shikorism/feature/home-v2
ホーム画面の微リニューアル
2019-02-11 13:17:34 +09:00
shibafu 7f5a4a06d9
Merge pull request #86 from unarist/feat/activitypub
ActivityPubResolverを追加
2019-02-11 13:16:29 +09:00
unarist d7c7f86ba5 CWもdescriptionに入れる 2019-02-11 03:07:52 +09:00
unarist ca212b547a Acceptに*/*を入れると無視されるので入れないようにする 2019-02-11 03:07:52 +09:00
unarist 3584625b47 Actorの取得失敗をちゃんと無視するように 2019-02-11 03:07:52 +09:00
unarist 1ba4999a83 不明なContentTypeや406はOGPにフォールバックする 2019-02-11 03:07:52 +09:00
shibafu 03e1c2d60c カード情報のリクエスト処理を共通化 2019-02-10 20:48:16 +09:00
shibafu ab0695ee8d xdebug.remote_autostartを使うと、デバッガーが不要な場合の処理時間が長くなりすぎるので止める 2019-02-10 18:58:58 +09:00
shibafu fcafc3c704 レビュー内容を部分的に反映
* Bootstrapのスタイルに乗せた
* 問題解決の方法を案内
* fixedに関わりたくなくなってきたので単にページ先頭要素にした
2019-02-10 17:00:35 +09:00
shibafu 7a606be3ba 別にIIFEである必要性ないじゃん 2019-02-09 23:38:53 +09:00
shibafu b4a7ec64dd デザインの微調整 2019-02-09 23:16:03 +09:00
unarist 5750eeb3a5 ActivityPubResolverを追加 2019-02-09 04:04:41 +09:00
shibafu b4dc07a9a3 サーバ内全体の日別総チェックイン数グラフをトップに設置 2019-02-09 02:34:53 +09:00
shibafu a77ac3f039 お惣菜コーナーのカード枠を削除
ユーザータイムラインに合わせた形
2019-02-09 00:50:47 +09:00
shibafu eef0eac887 サイトからのお知らせを左カラムに追いやった 2019-02-09 00:17:12 +09:00
Eai 7337f60491 お知らせがpinnedの場合ピン留めの表示をする (#58) 2019-02-08 23:45:25 +09:00
shibafu 85e9599654
Merge pull request #85 from shikorism/feature/profile
プロフィール設定機能の強化 (自己紹介文, URL)
2019-02-07 21:36:04 +09:00
shibafu 8a919ca62a
新規登録時に、Gravatarの利用についての案内を表示 (#84) 2019-02-07 21:35:09 +09:00
shibafu d105568c76
検索画面のページネーションURLに検索クエリが含まれるよう修正 (#83)
refs #82
2019-02-07 21:34:57 +09:00
shibafu 1f7723614d ホームで表示する自身の情報と、ユーザーページで表示するプロフィール情報を別のものにした 2019-02-07 00:52:44 +09:00
shibafu 41e810c788 プロフィール設定画面に自己紹介とURLを追加 2019-02-07 00:52:44 +09:00
shibafu 82af423c57 プロフィール欄に自己紹介とURLを掲載 2019-02-07 00:52:44 +09:00
shibafu 4346e1a701 usersテーブルに自己紹介とURLの列を追加 2019-02-07 00:52:44 +09:00
Eai 96199c9e46 年齢確認の画面でその他リンクをクリックできないように修正 (#81) 2019-02-05 22:33:11 +09:00
shibafu 4962244969
Merge pull request #77 from shikorism/feature/narou-resolver
NarouResolverを追加
2019-02-05 22:31:09 +09:00
unarist c417dabff2 Pixivのmode=mangaに対応 (#79) 2019-02-04 02:43:40 +09:00
shibafu d9bf673d85 作者名とあらすじの取得を試みる 2019-02-04 02:35:50 +09:00
shibafu 5961d3e27a ブラウザ設定でJavaScriptが無効になっている場合、メッセージを表示 2019-02-04 00:13:49 +09:00
unarist b57a272611 非ログイン時は年齢確認を表示するように (#78) 2019-02-04 00:10:14 +09:00
shibafu cbbb2605dd
Merge pull request #38 from eai04191/feature/profile-card
アイコンの横に名前が来るようにする
2019-02-03 21:58:01 +09:00
Eai e20bb75e00 PatreonResolverを追加 (#51) 2019-02-03 20:35:59 +09:00
eai04191 e226f43265 home でのみ省略表示するようにした 2019-02-03 16:47:16 +09:00
shibafu e887f2d83e NarouResolverを追加
refs #70
2019-02-03 01:10:29 +09:00
shibafu 1835776a9c
ログイン済の状態でログインページ等にアクセスした際のリダイレクト先が間違っていたので修正 (#75)
refs #69
2019-01-31 00:45:16 +09:00
shibafu 57715b9a82
タグ入力欄の高さが自動で拡張されるよう修正 (#74)
refs #71
2019-01-31 00:35:33 +09:00
shibafu e320f85c73
月間グラフの表示範囲が月末になると1ヶ月ズレるバグの修正 (#73)
refs #72
2019-01-31 00:14:26 +09:00
shibafu f5f4cbb5b6
Merge pull request #67 from shikorism/develop
Release 20190123.0045
2019-01-23 00:45:51 +09:00
shibafu 4ab82ff0e2 Revert "Merge pull request #30 from eai04191/feature-KomifloResolver"
This reverts commit b6bf1f99d8, reversing
changes made to ef563f8641.
2019-01-23 00:42:41 +09:00
shibafu 8c73bda2ac
Merge pull request #66 from shikorism/develop
Release 20190123.0030
2019-01-23 00:31:08 +09:00
shibafu 3c6f802b69
Merge pull request #41 from eai04191/feature/link-icon-flexbox
リンクアイコンの親要素をflexboxにしてリンクがアイコンから落ちないようにする
2019-01-23 00:21:32 +09:00
shibafu 895e9f4b15
OGPからタイトル情報が取れない場合はtitleタグから取得を試みる (#65)
refs #62
2019-01-23 00:04:10 +09:00
shibafu 648e171a57
Shift_JIS, EUC-JPでエンコードされたページのOGP取得対応 (#64)
refs #61
2019-01-22 12:46:44 +09:00
shibafu dc91180dd4
チェックイン要素の全体にword-wrapを設定 (#63)
refs #28
2019-01-22 12:46:25 +09:00
Eai bbbffcb39e DeviantArtResolverを追加 (#52) 2019-01-19 16:19:34 +09:00
shibafu 56831c78c3 Reformat time! 2019-01-19 03:02:37 +09:00
shibafu a30919991c "composer fix" の追加 2019-01-19 03:02:30 +09:00
shibafu 8aa2e6a779
Merge pull request #60 from shikorism/fix/56-broken-normalize 2019-01-19 02:27:07 +09:00
shibafu 34f45d1ce8
Merge pull request #59 from shikorism/feature/settings
ユーザー設定画面 (プロフィール, プライバシー関連)
2019-01-19 02:26:35 +09:00
shibafu 6d66425fc9 正規化対象のURLにクエリパラメータとURLフラグメントが両方とも含まれる場合、正規化時に順序が崩れて不正なURLになってしまうバグの修正
refs #56
2019-01-19 02:18:35 +09:00
shibafu 626c85c07d URL正規化のテストを追加 2019-01-19 02:18:35 +09:00
shibafu b6bf1f99d8
Merge pull request #30 from eai04191/feature-KomifloResolver
KomifloResolverに画像の取得を追加
2019-01-19 02:05:54 +09:00
eai04191 907eb87723 UTCのexpires_atをappのタイムゾーンに変換する
https://github.com/shikorism/tissue/pull/30#issuecomment-455174326
2019-01-19 01:41:11 +09:00
eai04191 72ec5d8d26 expires_atをCarbon化 2019-01-19 01:41:11 +09:00
eai04191 ca5be696c8 Komifloのメタデータに有効期限を設定する 2019-01-19 01:40:38 +09:00
eai04191 48ddac8c85 KomifloResolverに画像の取得を追加 2019-01-19 01:40:38 +09:00
shibafu a2580f29cc プロフィール設定とプライバシー設定を分割 2019-01-19 01:17:56 +09:00
shibafu 85cc865545 プロフィール設定の実装 2019-01-19 00:49:58 +09:00
shibafu 5d256519c6 プロフィール設定画面のページタイトルを追加 2019-01-19 00:49:58 +09:00
shibafu 53b459740f プライバシー設定の更新を実装 2019-01-19 00:49:58 +09:00
shibafu 550d897561 明日やろうは馬鹿やろう?知らねぇなぁ! 2019-01-19 00:49:53 +09:00
shibafu 27532685ba POST先ルート追加 2019-01-19 00:12:10 +09:00
shibafu 4654962aac プロフィール設定ページを作ろう 2019-01-19 00:12:10 +09:00
Eai ef563f8641 鍵垢だと概況データが出てこない問題を修正 (#53)
ref #50
2019-01-18 20:21:29 +09:00
Eai 7745b68dae php-cs-fixer のルールに single_quote を追加 (#54) 2019-01-18 20:00:47 +09:00
Eai e5ea0528a8 docker-compose.debug.ymlを追加 (#55)
* docker-compose.debug.ymlを追加

* README追記
2019-01-18 20:00:24 +09:00
Eai 4e1eec66be FanzaResolver追加 (#43)
FanzaのOGP画像は `ps.jpg` か `pr.jpg` で終わっている。 `pl.jpg` で高解像度なものが取得できる。
2019-01-18 00:16:02 +09:00
shibafu a33a0e542c Fix NijieResolverText (#42)
とりあえず通るようにしただけ
2019-01-17 23:26:35 +09:00
Eai 473280d9d2 Linux環境で権限がないためファイルを書き込めない問題を修正 (#49) 2019-01-17 22:12:26 +09:00
Eai 73c697f119 構築手順の最後に.envの読み直しを追記 (#47) 2019-01-17 18:15:37 +09:00
shibafu 09482ca2c5
Merge pull request #45 from shikorism/develop
Release 20190117.0100
2019-01-17 01:05:04 +09:00
shibafu 3a1dc72cf7
チェックイン修正時のバリデーションエラーで新規作成に飛ばされてしまうバグの修正 (#44)
refs #34
2019-01-17 01:01:42 +09:00
Eai b04f167709 パブリックタイムラインと検索画面で出るチェックインユーザーの名前をdisplay_nameにする (#39)
現状では設定できないため同じだがこちらのほうが好ましいはず。
2019-01-17 00:12:25 +09:00
shibafu a3b328b55f
メール欄のtypeをemailに変更 (#37)
* ログインフォームのメール欄のtypeをemailに変更

* 新規登録画面のメール欄のtypeをemailに変更

* パスワード再発行画面のメール欄のtypeをemailに変更

* パスワード再発行(実行)画面のメール欄のtypeをemailに変更
2019-01-17 00:00:33 +09:00
shibafu 497c19d06d パスワード再発行(実行)画面のメール欄のtypeをemailに変更 2019-01-16 23:57:30 +09:00
eai04191 ade52f40f4 パスワード再発行画面のメール欄のtypeをemailに変更 2019-01-16 23:20:19 +09:00
eai04191 c38d3fa799 新規登録画面のメール欄のtypeをemailに変更 2019-01-16 23:20:06 +09:00
shibafu 2a91aac569 chmod +x 2019-01-16 22:57:26 +09:00
eai04191 f367ec212f リンクアイコンの親要素をflexboxにしてリンクがアイコンから落ちないようにする 2019-01-16 19:17:30 +09:00
eai04191 735c7c289a Bootstrap v4.1.1 から v4.2.1 に更新 2019-01-16 16:33:00 +09:00
eai04191 cffe539832 アイコンの横に名前が来るように修正 2019-01-16 07:00:12 +09:00
eai04191 2191a96cac Bootstrap v4.1.1 から v4.2.1 に更新 2019-01-16 06:59:10 +09:00
eai04191 64f8b47ae0 ログインフォームのメール欄のtypeをemailに変更 2019-01-16 05:42:46 +09:00
shibafu 2ca6c4c60d
Dockerコンテナ内にXdebugを導入 (#33)
* コンテナにxdebugをインストール
* env fileをDockerに読ませるようにした
* 環境変数 APP_DEBUG に応じてXdebugをロードしてApacheを起動するようにした
* シェルスクリプトのWindows対策 (.gitattribute)
2019-01-16 00:42:05 +09:00
shibafu 0d4a61ef15 Merge pull request #32 from eai04191/feature-Metadata-Expires 2019-01-16 00:38:10 +09:00
shibafu cef23a64cb メタデータの再取得判定をチェックイン時の処理にも実装 2019-01-16 00:31:54 +09:00
shibafu cd26ef6236 メタデータの更新時に多重登録されないようにした 2019-01-16 00:31:54 +09:00
shibafu 810eea2a59 Metadata.expires_atをCarbon化 2019-01-16 00:31:54 +09:00
shibafu acb9b5821d expires_atに有効な値が設定されている場合のみ、メタデータの有効期限判定を行う 2019-01-16 00:31:54 +09:00
shibafu 5f01cc3430 メタデータエンティティにexpires_atプロパティを追加 2019-01-16 00:31:54 +09:00
eai04191 938a4d6957 metadataテーブルにexpires_atカラムを追加
メタデータの有効期限が現在より過去の場合、メタデータを再取得する
2019-01-15 16:51:50 +09:00
eai04191 a3813f19cf Merge remote-tracking branch 'upstream/develop' into develop 2019-01-15 00:08:40 +09:00
shibafu faf0755ebd Reformat 2019-01-15 00:05:01 +09:00
shibafu a2f797cbbe 独断と偏見のphp-cs-fixerルールを追加 2019-01-15 00:02:44 +09:00
shibafu 8c6cc0692c
Merge pull request #29 from eai04191/feature-FantiaResolver
FantiaResolverを追加
2019-01-15 00:01:52 +09:00
eai04191 dcf31865a1 拡張子がpngの場合に対応 2019-01-14 23:50:15 +09:00
eai04191 3dedb57fe4 正規表現を修正 2019-01-14 23:46:39 +09:00
eai04191 f134cbefa8 投稿に画像がない場合エラーが発生するのを修正 2019-01-14 23:08:37 +09:00
eai04191 72ab8bf101 FantiaResolverを追加 2019-01-14 22:55:01 +09:00
eai04191 11836ddd43 Merge remote-tracking branch 'upstream/develop' into develop 2019-01-14 21:38:34 +09:00
shibafu 5c6417cdbe
Merge pull request #25 from eai04191/feature-PixivResolver
PixivResolverの追加
2019-01-14 18:49:14 +09:00
mohemohe 0e410ef342 composer installでdistから取れるようにする (#26) 2019-01-14 18:37:42 +09:00
eai04191 d6e981ac39 不要なセミコロンの削除 2019-01-14 18:35:34 +09:00
eai04191 98e933b833 変数名をcamelCase に統一 2019-01-14 18:34:33 +09:00
eai04191 6ff247acd7 proxizeを修正
- ドキュメントコメントを修正
- 引数名をより正確なものに修正
2019-01-14 18:27:21 +09:00
eai04191 2d04ed8dd7 thumbnailToMasterUrlを修正
- ドキュメントコメントを修正
- 変数名をより正確なものに修正
2019-01-14 18:27:21 +09:00
eai04191 d359a41033 メソッド名をcamelCaseに変更 2019-01-14 18:27:04 +09:00
shibafu 2299ac3fe7 開発環境向けの措置として、reCAPTCHAは任意設定とする 2019-01-14 18:03:58 +09:00
shibafu fcdb9d7aba reCAPTCHAの設置 2019-01-14 18:03:58 +09:00
shibafu e6abcc4402 依存関係にreCAPTCHA用パッケージを追加 2019-01-14 18:03:58 +09:00
eai04191 b0a7504691 Loggingの削除・メソッドの説明をまともに 2019-01-14 16:11:14 +09:00
eai04191 a645cb497f 謝辞を追加 2019-01-14 16:03:46 +09:00
eai04191 6105f6c860 PixivResolverを追加 2019-01-14 16:01:58 +09:00
Eai 9eb42f1991 不要なインポートの削除 (#23) 2019-01-14 14:19:43 +09:00
eai04191 dfea7f2f24 不要なインポートの削除 2019-01-14 11:29:16 +09:00
shibafu 7441c26694
Merge pull request #22 from shikorism/develop
Release 20190114.0950
2019-01-14 09:51:33 +09:00
shibafu 630be41833
Merge pull request #21 from eai04191/feature-DLsiteResolver
DLsiteResolverを追加
2019-01-14 09:39:58 +09:00
shibafu c4a69cccbe
Merge pull request #20 from eai04191/feature-dropdown-user-link
ドロップダウンにプロフィールへのリンクを追加
2019-01-14 08:35:54 +09:00
eai04191 cb3f060ba6 DLsiteResolverを追加 2019-01-14 04:22:40 +09:00
eai04191 4d7b70f9ad ドロップダウンにプロフィールへのリンクを追加 2019-01-14 02:16:14 +09:00
shibafu 3bb6bf718e
Merge pull request #18 from eai04191/issue-5
#17 開発環境の構築に関するメモを追加
2019-01-14 01:36:19 +09:00
eai04191 fc709a6624 READMEに開発環境の構築方法を追加 2019-01-14 01:23:19 +09:00
eai04191 8d5363e978 ComposerのためにDockerfileにgitを追加 2019-01-14 01:23:07 +09:00
eai04191 71137e9ab4 余分なスペースの削除 2019-01-14 01:02:35 +09:00
shibafu f7a95befbe
オカズリンクの上限を2000文字に拡張 (#16)
* マイグレーションのために依存関係を追加
* Ejaculations.linkのデータ型をTEXTに変更
* オカズリンクに2000文字の上限値を設定
2019-01-13 23:58:11 +09:00
shibafu 908790b53d Merge branch 'develop' 2019-01-12 00:51:18 +09:00
shibafu 20799dd757 お惣菜コーナーの表示件数を少し増やす 2019-01-12 00:14:51 +09:00
shibafu ca02f21812 チェックイン時のメタデータ取得に失敗した際、ログだけ残して終了する 2019-01-11 22:39:54 +09:00
shibafu 168ef1c5f6 チェックインページのタイトル内日付フォーマットをちょっと変更 2019-01-10 01:39:10 +09:00
shibafu 3c2e475e41 Merge branch 'develop' 2019-01-10 01:36:13 +09:00
shibafu 581c1ed952 メロンから取得したサムネイルからcensored flagらしきパラメータを外す 2019-01-10 01:29:26 +09:00
shibafu ad5fbc7ada ページタイトルを設定 2019-01-08 23:27:48 +09:00
shibafu cf1757319e Merge branch 'develop' 2019-01-05 01:05:25 +09:00
shibafu b39b43e705
時間帯・曜日別チェックイン回数グラフ (#14)
* 曜日別回数グラフの追加
* 時間別回数グラフの追加
2019-01-02 14:44:31 +09:00
shibafu bcc9f3acda Merge branch 'develop' 2018-12-17 23:27:46 +09:00
shibafu 911957b283 nijieのview_popup.php URLからもIDが引けるので正規化して対応 2018-12-17 23:27:19 +09:00
shibafu b9e29cc283 Merge branch 'develop' 2018-12-14 00:36:58 +09:00
shibafu 316b453cca Laravel 5.5.44にアップデート
ついでにcomposer.jsonをlaravel/laravel:5.5の現状に合わせた
2018-12-14 00:25:19 +09:00
shibafu e6b28993de parsedown/laravelへの依存を削除し、同等のBladeディレクティブを移植 2018-12-13 23:49:26 +09:00
shibafu e875d5da02 Merge branch 'develop' 2018-11-20 23:33:07 +09:00
shibafu 233a54eb3e Iwaraのカード表示対応
refs #12
2018-11-20 23:31:57 +09:00
shibafu 515e24c4e4 Merge branch 'develop' 2018-09-11 23:22:29 +09:00
shibafu af4b60d6e1 LaravelドキュメントのDeploymentsに書かれているコマンドを実行するスクリプト 2018-09-11 23:19:41 +09:00
shibafu 5bb44ab232 検索ボックスにとりあえずrequiredを付けた 2018-09-11 23:10:30 +09:00
shibafu 874e88cc56 プロフィールの「よく使っているタグ」を検索リンク化 2018-09-11 23:08:11 +09:00
shibafu bdb1640ceb チェックインのタグを検索リンク化 2018-09-11 23:05:01 +09:00
shibafu c52046d51e オカズリンク入力欄のオートコンプリートを無効化 2018-09-08 00:19:50 +09:00
shibafu 69f212d705 検索ページの初期実装 2018-09-06 23:48:54 +09:00
shibafu 2441fe78b6 Merge branch 'develop' 2018-06-13 21:56:40 +09:00
shibafu 9646f90ce3 通販サイトのメタデータ対応 2018-06-13 01:00:24 +09:00
shibafu 9bd22d9f77 OGPResolverでTwitter Cardsの解析も行えるようにした (#9) 2018-06-13 01:00:11 +09:00
shibafu a0e4063c47 なんか変わってた 2018-06-13 00:25:34 +09:00
shibafu 0882063c0b ログアウトメニューを右寄せにした 2018-06-12 22:48:43 +09:00
shibafu b4e40ab748 Bootstrap 4.1にアップデート (#5) 2018-06-12 22:44:07 +09:00
shibafu 6609965360 Fix typo 2018-06-12 21:52:10 +09:00
shibafu 9705c2ce5a よく使っているタグを表示する機能 2018-06-09 00:30:41 +09:00
shibafu bd93d9ec24 varchar(255)で収まるわけないので作りなおす 2018-06-08 01:44:39 +09:00
shibafu 55bd35ea49 Merge branch 'develop' 2018-06-08 01:00:18 +09:00
shibafu 4dc4efe10d エロ漫画のタイトルくらいは取りたかった 2018-06-08 00:44:42 +09:00
shibafu dfe149e969 オカズリンクのデータを保存するようにした (#4) 2018-06-07 23:46:40 +09:00
shibafu f51aaea94c お惣菜コーナーにも「同じオカズでチェックイン」ボタンを表示する 2018-06-07 02:23:09 +09:00
shibafu 1dea0a077c 他人のチェックインにも「同じオカズでチェックイン」ボタンを表示する (#8) 2018-06-07 02:21:40 +09:00
shibafu d143dc4d84 ドッカーン 2018-06-05 23:45:29 +09:00
shibafu e033816eab Merge branch 'develop' 2018-06-02 23:33:47 +09:00
shibafu 503e8ba093 「同じオカズでチェックイン」ボタンの追加 2018-06-02 23:33:16 +09:00
shibafu d224e6bba4 gifとmp4の場合はサムネイルを取得させない 2018-04-15 23:16:19 +09:00
shibafu 3b2e81818b sp.nijie.infoの画像情報を正しく取得できるようにした
fix #7
2018-04-15 21:46:49 +09:00
shibafu 7ca0acacb4 コンテンツ情報取得の実装をapi.phpから剥がした 2018-04-15 03:29:00 +09:00
shibafu 88456bc609 Merge branch 'develop' 2018-04-11 01:18:01 +09:00
shibafu 0f39b502e8 オカズリンクのサムネイル取得にて、特定のJSONのデコード前に改行コードをエスケープするようにした 2018-04-11 01:17:52 +09:00
shibafu 46f049c2b8 Merge branch 'develop' 2018-03-06 23:50:12 +09:00
shibafu 9cdfadf12c オカズリンクのカード幅を調整
fix #3
2018-03-06 23:49:34 +09:00
shibafu bc57a482be シコ草を日曜始まりに変更 2018-03-06 23:36:45 +09:00
shibafu ba53156beb 会員登録リンクをヘッダーに追加
fix #2
2018-03-06 23:36:41 +09:00
Shibafu 5b2427a2c9
チェックイン画面でクエリパラメータを受け付ける (#6)
* チェックイン画面でクエリパラメータを受け付けるようにした

* バリデーションエラー吐いたときにクエリパラメータが蘇らないようにした
2018-03-06 22:43:49 +09:00
shibafu 277ee90379 お惣菜コーナーのユーザーURLを正しいものに修正 2018-01-09 21:56:59 +09:00
shibafu 336d368369 タグ未入力時に空白のタグが生成されるバグの修正 2018-01-08 15:23:58 +09:00
shibafu 917675f9bd Merge branch 'develop' 2018-01-08 14:51:49 +09:00
shibafu 0c216e79c2 タグをEager Loadするようにした 2018-01-08 10:28:12 +09:00
shibafu e0942889e9 お惣菜コーナーにタグを表示 2018-01-08 08:59:08 +09:00
shibafu 24a3b0ebb5 チェックイン編集画面もタグ登録に対応 2018-01-08 08:56:17 +09:00
shibafu b1dcc36565 タグ登録機能の追加 2018-01-08 08:50:22 +09:00
shibafu d7b16cd6d5 タグ入力欄っぽいものだけ作った 2018-01-08 01:02:27 +09:00
shibafu 6bfc1425a6 なぜ固定件数のお知らせ取得にpaginateを使っていた? 2018-01-07 22:45:57 +09:00
shibafu 767947ee6c Debugbarを導入 2018-01-07 22:44:06 +09:00
shibafu efd5eab5e6 非公開ユーザの考慮漏れ 2018-01-07 22:42:30 +09:00
shibafu eb1884200b お惣菜コーナーを作った 2018-01-07 22:19:33 +09:00
shibafu 6c90cc2383 チェックインの個別ページがログイン要求していたのを解除 2018-01-06 19:50:16 +09:00
shibafu ef38485dfe カードリンクを別ウィンドウで開くようにした 2018-01-06 01:56:49 +09:00
shibafu b5a723cb3c カードタイトルを太字に 2018-01-06 00:48:25 +09:00
shibafu 2bd56a8606 オカズリンクを含むチェックインのみを表示するページの作成 2018-01-06 00:35:04 +09:00
shibafu 7a386d4d89 一部サイトに対するサムネイルURL解決の特殊処理を仕込んだ 2018-01-05 23:47:01 +09:00
shibafu f2ed4f85ee /api/ogp を /api/checkin/card に変更 2018-01-05 22:43:33 +09:00
shibafu 69f619e2af 未ログイントップにお知らせを置いてみた 2018-01-05 22:27:16 +09:00
shibafu 3ea9476aa8 本番時はキャッシュしてもいいんじゃない? 2018-01-05 00:54:33 +09:00
shibafu b562b3b400 オカズリンクの一次対応 2018-01-05 00:26:48 +09:00
shibafu 2fe3d7ac49 チェックイン修正を雑に書いた
これ日時はいじれないほうが良い気がするな
2018-01-04 16:53:33 +09:00
shibafu 7a3a1c1ada 年間チェックイングラフの追加 2018-01-04 15:58:50 +09:00
shibafu c04ec89c3e 月別チェックイン回数グラフ 2018-01-04 14:50:14 +09:00
shibafu bd19018699 複数行入力可能な項目は、処理前に改行コードを正規化する
fix #1
2018-01-02 23:37:27 +09:00
shibafu 4f475aed3e メール送信にSparkPostを使用するためのセットアップ 2018-01-02 17:48:42 +09:00
shibafu 6ace47c27e Update README.md 2017-11-07 01:16:15 +09:00
shibafu 88456abb15 ちょっとまってPinnedがむしろ下に潜り込んでた 2017-11-07 00:57:33 +09:00
shibafu 9d6a76a7f8 ヒートマップがページからはみ出て悲しいのでoverflow付けた 2017-11-07 00:39:07 +09:00
shibafu 6d0472c14b 有名なヒートマップのようなやつを搭載した 2017-11-07 00:22:40 +09:00
shibafu 58258f8fe3 Bootstrap 4への移行完了 2017-11-06 00:49:10 +09:00
shibafu 2038b5e7c3 チェックイン後の遷移先をそのチェックインのページに変更
将来的にそのチェックインに関連する通知を出したくなった時に都合がいいので
2017-11-05 23:06:03 +09:00
shibafu 95204736ef ユーザの本人判定をModelに逃した 2017-11-05 22:29:09 +09:00
shibafu 7e9501ab9d 非公開アカウント対応 2017-11-05 22:24:25 +09:00
shibafu d0c9e3a3af チェックイン単独のページを追加 2017-11-05 21:49:27 +09:00
shibafu fca4c21d3a ヘッダーのコンテンツ幅を縮めた 2017-11-05 19:51:31 +09:00
shibafu 016d4d8e3f word-wrap何もしてなかった 2017-11-05 19:31:50 +09:00
shibafu 94918fc337 チェックイン画面のレイアウト変更
別にレイアウト変わってないので焼き直しが正しい
2017-11-05 19:14:54 +09:00
shibafu 723bb236c9 プロフィール画面が非ログイン時にコケないようにした 2017-11-05 10:32:16 +09:00
shibafu 6ed0938694 プロフィールの左カラムにある情報に関する処理をリファクタリング 2017-11-05 01:26:52 +09:00
shibafu 53f34c12cc チェックインノートの改行を表示に反映し、URLっぽい文字列をリンク化するようにした 2017-11-03 23:47:38 +09:00
shibafu efea60fc81 Parsedownをプラグイン経由で使うようにした 2017-11-03 23:23:36 +09:00
shibafu d94c444b55 お知らせ画面の追加 2017-11-03 20:38:09 +09:00
shibafu edcc2bceaf profileルートの名前を変更 2017-11-03 18:10:50 +09:00
shibafu abf8b05253 チェックイン削除機能の実装 2017-11-03 17:48:58 +09:00
shibafu e9b19e7be1 プロフィール画面のレイアウト変更 2017-10-30 22:03:34 +09:00
shibafu 70421eabb0 Fix Typo 2017-10-30 20:17:25 +09:00
shibafu b5f04cb153 ホーム画面のレイアウト変更 2017-10-23 00:03:24 +09:00
shibafu 70ae2fd982 Bootstrapを用いたレイアウトの投入開始 2017-10-22 23:13:21 +09:00
shibafu 1dbc573833 経過時間のフォーマットを日から総日数に修正 2017-10-22 20:35:09 +09:00
shibafu eb6487c4cf Laravel 5.5にアップデート 2017-10-22 20:22:43 +09:00
shibafu df07aecd88 旧レイアウトの退避 2017-10-22 19:41:41 +09:00
shibafu 12d06dc88b 概況欄の時間表記が狂っていたため、フォーマットの担当をDBからPHPに移した 2017-09-09 02:10:51 +09:00
399 changed files with 102410 additions and 24796 deletions

177
.circleci/config.yml Normal file
View File

@ -0,0 +1,177 @@
version: 2.1
executors:
build:
docker:
- image: circleci/php:7.3-node-browsers
environment:
APP_DEBUG: true
APP_ENV: testing
APP_KEY: base64:f2tcw34GKT8EOtb5myZxJ8QLdgNivmyPhoQIPY2YfK8=
DB_CONNECTION: pgsql
DB_DATABASE: tissue
DB_USERNAME: tissue
DB_PASSWORD: tissue
- image: circleci/postgres:10-alpine
environment:
POSTGRES_DB: tissue
POSTGRES_USER: tissue
POSTGRES_PASSWORD: tissue
commands:
initialize:
steps:
- checkout
- run: sudo apt update
- run: sudo apt install -y libpq-dev
- run: sudo pecl install -f xdebug-2.9.8 && sudo docker-php-ext-enable xdebug
- run: sudo docker-php-ext-install zip
- run: sudo docker-php-ext-install pdo_pgsql
- run:
command: |
curl -sSL "https://nodejs.org/dist/v12.16.3/node-v12.16.3-linux-x64.tar.xz" | sudo tar --strip-components=2 -xJ -C /usr/local/bin/ node-v12.16.3-linux-x64/bin/node
curl https://www.npmjs.com/install.sh | sudo bash
restore_composer:
steps:
- restore_cache:
keys:
- v1-dependencies-{{ checksum "composer.json" }}
- v1-dependencies-
save_composer:
steps:
- save_cache:
key: v1-dependencies-{{ checksum "composer.json" }}
paths:
- ./vendor
restore_npm:
steps:
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
- v1-dependencies-
save_npm:
steps:
- save_cache:
key: v1-dependencies-{{ checksum "package.json" }}
paths:
- ./node_modules
- ~/.yarn
jobs:
build:
executor: build
steps:
- initialize
- restore_composer
- run: composer install -n --prefer-dist
- save_composer
- restore_npm
- run: yarn install
- save_npm
- run: yarn run prod
- persist_to_workspace:
root: .
paths:
- public
test:
executor: build
steps:
- initialize
- restore_composer
- restore_npm
- attach_workspace:
at: .
- run: php artisan migrate
# Run linter
- run:
command: |
mkdir -p /tmp/php-cs-fixer
./vendor/bin/php-cs-fixer fix --dry-run --diff --format=junit > /tmp/php-cs-fixer/php-cs-fixer.xml
when: always
- store_test_results:
path: /tmp/php-cs-fixer
# Run stylelint
- run:
name: stylelint
command: yarn run stylelint
when: always
# Run eslint
- run:
name: eslint
command: yarn run eslint
when: always
# Run unit test
- run:
command: |
mkdir -p /tmp/phpunit
./vendor/bin/phpunit --log-junit /tmp/phpunit/phpunit.xml --coverage-clover=/tmp/phpunit/coverage.xml
when: always
- store_test_results:
path: /tmp/phpunit
- store_artifacts:
path: /tmp/phpunit/coverage.xml
# Upload coverage
- run:
command: bash <(curl -s https://codecov.io/bash) -f /tmp/phpunit/coverage.xml
when: always
test_resolver:
executor: build
environment:
TEST_USE_HTTP_MOCK: false
steps:
- initialize
- restore_composer
- attach_workspace:
at: .
- run: php artisan migrate
# Run unit test
- run:
command: |
mkdir -p /tmp/phpunit
./vendor/bin/phpunit --testsuite MetadataResolver --log-junit /tmp/phpunit/phpunit.xml --coverage-clover=/tmp/phpunit/coverage.xml
when: always
- store_test_results:
path: /tmp/phpunit
- store_artifacts:
path: /tmp/phpunit/coverage.xml
workflows:
version: 2.1
test:
jobs:
- build
- test:
requires:
- build
scheduled_resolver_test:
triggers:
- schedule:
cron: "4 0 * * 1"
filters:
branches:
only:
- develop
jobs:
- build
- test_resolver:
requires:
- build

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
.idea
.git
.gitignore
.gitattributes

21
.editorconfig Normal file
View File

@ -0,0 +1,21 @@
root = true
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[*.json]
indent_size = 2
[composer.json]
indent_size = 4

View File

@ -1,16 +1,23 @@
APP_NAME=Laravel
APP_NAME=Tissue
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
LOG_CHANNEL=stack
# テストにモックを使用するか falseの場合は実際のHTML等を取得してテストする
TEST_USE_HTTP_MOCK=true
# テスト用のスナップショットを更新する場合はtrueにする (TEST_USE_HTTP_MOCKと重複させないよう注意)
TEST_UPDATE_SNAPSHOT=false
DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=tissue
DB_USERNAME=tissue
DB_PASSWORD=tissue
BROADCAST_DRIVER=log
CACHE_DRIVER=file
@ -22,12 +29,31 @@ REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_HOST=smtp.sparkpostmail.com
MAIL_PORT=587
MAIL_USERNAME=SMTP_Injection
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=support@mail.shikorism.net
MAIL_FROM_NAME=Tissue
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
SPARKPOST_SECRET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# (Optional) reCAPTCHA Key
# https://www.google.com/recaptcha
NOCAPTCHA_SECRET=
NOCAPTCHA_SITEKEY=
SENTRY_LARAVEL_DSN=

38
.eslintrc.js vendored Normal file
View File

@ -0,0 +1,38 @@
module.exports = {
env: {
browser: true,
es2020: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'prettier/@typescript-eslint',
'prettier/react',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 11,
ecmaFeatures: {
jsx: true,
},
sourceType: 'module',
},
plugins: ['prettier', 'react', '@typescript-eslint', 'jquery'],
rules: {
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'jquery/no-ajax': 2,
'jquery/no-ajax-events': 2,
'react/prop-types': 0,
},
settings: {
react: {
version: 'detect',
},
},
};

1
.gitattributes vendored
View File

@ -3,3 +3,4 @@
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore
*.sh text eol=lf

14
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,14 @@
version: 2
updates:
# Maintain dependencies for npm
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
# Maintain dependencies for Composer
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "daily"

15
.gitignore vendored
View File

@ -1,13 +1,26 @@
/node_modules
/public/css
/public/fonts
/public/js
/public/hot
/public/storage
/public/mix-manifest.json
/public/report.html
/public/apidoc.html
/storage/*.key
/vendor
/.idea
/.vscode
/.vagrant
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
.env
*.iml
.env.backup
.phpunit.result.cache
*.iml
.php_cs
.php_cs.cache
.phpstorm.meta.php
_ide_helper*.php

27
.php_cs.dist Normal file
View File

@ -0,0 +1,27 @@
<?php
return \PhpCsFixer\Config::create()
->setRules([
'@PSR2' => true,
'array_syntax' => [
'syntax' => 'short'
],
'blank_line_before_return' => true,
'function_typehint_space' => true,
'method_separation' => true,
'ordered_imports' => true,
'return_type_declaration' => true,
'new_with_braces' => true,
'no_empty_statement' => true,
'standardize_not_equals' => true,
'single_quote' => true
])
->setFinder(
\PhpCsFixer\Finder::create()
->exclude('bootstrap/cache')
->exclude('resources/views')
->exclude('storage')
->exclude('vendor')
->exclude('node_modules')
->in(__DIR__)
);

5
.prettierrc Normal file
View File

@ -0,0 +1,5 @@
{
"arrowParens": "always",
"singleQuote": true,
"printWidth": 120
}

1
.stylelintignore Normal file
View File

@ -0,0 +1 @@
/tests/fixture/*

33
Dockerfile Normal file
View File

@ -0,0 +1,33 @@
FROM node:10-jessie as node
FROM php:7.3-apache
ENV APACHE_DOCUMENT_ROOT /var/www/html/public
RUN apt-get update \
&& apt-get install -y git libpq-dev unzip libicu-dev \
&& docker-php-ext-install pdo_pgsql intl \
&& pecl install xdebug \
&& curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer \
&& sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
&& sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \
&& a2enmod rewrite
COPY dist/bin /usr/local/bin/
COPY dist/php.d /usr/local/etc/php/php.d/
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=node /opt/yarn-* /opt/yarn
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -s ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
ENTRYPOINT ["tissue-entrypoint.sh"]
CMD ["apache2-foreground"]
WORKDIR /var/www/html

1
Procfile Normal file
View File

@ -0,0 +1 @@
web: vendor/bin/heroku-php-apache2 public/

100
README.md
View File

@ -1,19 +1,101 @@
Tissue
====
# Tissue
a.k.a. shikorism.net
シコリズムネットにて提供している夜のライフログサービスです。
シコリズムネットにて提供している夜のライフログサービスです。
(思想的には [shibafu528/SperMaster](https://github.com/shibafu528/SperMaster) の後継となります)
## 構成
* Laravel 5.4
* Materialize 0.99.0 (Materialでデザインする気が失せたので変更予定)
- Laravel 6
- Bootstrap 4.4.1
## 実行環境
* PHP 7.1
* PostgreSQL 9.6
- PHP 7.3
- PostgreSQL 9.6
## 開発環境の構築
Docker を用いた開発環境の構築方法です。
1. `.env` ファイルを用意します。`.env.example` をコピーすることで用意ができます。
2. Docker イメージをビルドします
```
docker-compose build
```
3. Docker コンテナを起動します。
```
docker-compose up -d
```
4. Composer と yarn を使い必要なライブラリをインストールします。
```
docker-compose exec web composer install
docker-compose exec web yarn install
```
5. 暗号化キーの作成と、データベースのマイグレーションを行います。
```
docker-compose exec web php artisan key:generate
docker-compose exec web php artisan migrate
```
6. ファイルに書き込めるように権限を設定します。
```
docker-compose exec web chown -R www-data /var/www/html/storage
```
7. アセットをビルドします。
```
docker-compose exec web yarn dev
```
8. 最後に `.env` を読み込み直すために起動し直します。
```
docker-compose up -d
```
これで準備は完了です。Tissue が動いていれば `http://localhost:4545/` でアクセスができます。
## デバッグ実行
```
docker-compose -f docker-compose.yml -f docker-compose.debug.yml up -d
```
で起動することにより、DB のポート`5432`を開放してホストマシンから接続できるようになります。
## アセットのリアルタイムビルド
`yarn watch`を使うとソースファイルを監視して差分があると差分ビルドしてくれます。フロント開発時は活用しましょう。
```
docker-compose run --rm web yarn watch
```
もしファイル変更時に更新されない場合は`yarn watch-poll`を試してみてください。
現在Docker環境でのHMRはサポートしてません。Docker外ならおそらく動くでしょう。
その他詳しくはlaravel-mixのドキュメントなどを当たってください。
## phpunit によるテスト
変更をしたらPull Requestを投げる前にテストが通ることを確認してください。
テストは以下のコマンドで実行できます。
```
docker-compose exec web composer test
```
## 環境構築上の諸注意
* 初版時点では、DBサーバとしてPostgreSQLを使うよう .env ファイルを設定するくらいです。
当分、PostgreSQLから変える気はないので専用SQL等を平気で使います。
- 初版時点では、DB サーバとして PostgreSQL を使うよう .env ファイルを設定するくらいです。
当分、PostgreSQL から変える気はないので専用 SQL 等を平気で使います。

39
app/CheckinWebhook.php Normal file
View File

@ -0,0 +1,39 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;
class CheckinWebhook extends Model
{
use SoftDeletes;
/** @var int ユーザーごとの作成数制限 */
const PER_USER_LIMIT = 10;
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = ['name'];
protected static function boot()
{
parent::boot();
self::creating(function (CheckinWebhook $webhook) {
$webhook->id = Str::random(64);
});
}
public function user()
{
return $this->belongsTo(User::class);
}
public function isAvailable()
{
return $this->user !== null;
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace App\Console\Commands;
use App\Tag;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class DedupTags extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tissue:tag:dedup {--dry-run}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Deduplicate tags';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ($this->option('dry-run')) {
$this->warn('dry-runモードで実行します。');
} else {
if (!$this->confirm('dry-runオプションが付いてないけど、本当に実行しますか')) {
return;
}
}
DB::transaction(function () {
$duplicatedTags = DB::table('tags')
->select('name', DB::raw('count(*)'))
->groupBy('name')
->having(DB::raw('count(*)'), '>=', 2)
->get();
$this->info($duplicatedTags->count() . ' duplicated tags found.');
foreach ($duplicatedTags as $tag) {
$this->line('Tag name: ' . $tag->name);
$tagIds = Tag::where('name', $tag->name)->orderBy('id')->pluck('id');
$newId = $tagIds->first();
$dropIds = $tagIds->slice(1);
$this->line(' New ID: ' . $newId);
$this->line(' Drop IDs: ' . $dropIds->implode(', '));
if ($this->option('dry-run')) {
continue;
}
// 同じタグ名でIDが違うものについて、全て統一する
foreach (['ejaculation_tag', 'metadata_tag'] as $table) {
DB::table($table)
->whereIn('tag_id', $dropIds)
->update(['tag_id' => $newId]);
}
DB::table('tags')->whereIn('id', $dropIds)->delete();
// 統一した上で、重複しているレコードを削除する
DB::delete(
<<<SQL
DELETE FROM ejaculation_tag
WHERE id IN (
SELECT id
FROM (
SELECT id, row_number() OVER (PARTITION BY ejaculation_id, tag_id ORDER BY id) AS ord
FROM ejaculation_tag
) t
WHERE ord > 1
)
SQL
);
DB::delete(
<<<SQL
DELETE FROM metadata_tag
WHERE id IN (
SELECT id
FROM (
SELECT id, row_number() OVER (PARTITION BY metadata_url, tag_id ORDER BY id) AS ord
FROM metadata_tag
) t
WHERE ord > 1
)
SQL
);
}
});
$this->info('Done!');
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
class DemoteUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tissue:user:demote {username}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Demote admin to user';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$user = User::where('name', $this->argument('username'))->first();
if ($user === null) {
$this->error('No user with such username');
return 1;
}
if (!$user->is_admin) {
$this->info('@' . $user->name . ' is already an user.');
return 0;
}
$user->is_admin = false;
if ($user->save()) {
$this->info('@' . $user->name . ' is an user now.');
} else {
$this->error('Something happened.');
}
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Console\Commands;
use App\Tag;
use App\Utilities\Formatter;
use DB;
use Illuminate\Console\Command;
class NormalizeTags extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tissue:tag:normalize';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Normalize tags';
private $formatter;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(Formatter $formatter)
{
parent::__construct();
$this->formatter = $formatter;
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$start = hrtime(true);
DB::transaction(function () {
/** @var Tag $tag */
foreach (Tag::query()->cursor() as $tag) {
$normalizedName = $this->formatter->normalizeTagName($tag->name);
$this->line("{$tag->name} : {$normalizedName}");
$tag->normalized_name = $normalizedName;
$tag->save();
}
});
$elapsed = (hrtime(true) - $start) / 1e+9;
$this->info("Done! ({$elapsed} sec)");
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
class PromoteUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tissue:user:promote {username}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Promote user to admin';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$user = User::where('name', $this->argument('username'))->first();
if ($user === null) {
$this->error('No user with such username');
return 1;
}
if ($user->is_admin) {
$this->info('@' . $user->name . ' is already an administrator.');
return 0;
}
$user->is_admin = true;
if ($user->save()) {
$this->info('@' . $user->name . ' is an administrator now.');
} else {
$this->error('Something happened.');
}
}
}

View File

@ -2,6 +2,8 @@
namespace App\Console;
use App\Console\Commands\DemoteUser;
use App\Console\Commands\PromoteUser;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -35,6 +37,8 @@ class Kernel extends ConsoleKernel
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

24
app/ContentProvider.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ContentProvider extends Model
{
public $incrementing = false;
protected $primaryKey = 'host';
protected $keyType = 'string';
protected $fillable = [
'host',
'robots',
'robots_cached_at',
];
protected $dates = [
'created_at',
'updated_at',
'robots_cached_at',
];
}

18
app/DeactivatedUser.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* 削除済Userのユーザー名履歴
*/
class DeactivatedUser extends Model
{
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = [
'name'
];
}

View File

@ -2,15 +2,136 @@
namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
class Ejaculation extends Model
{
//
use HasEagerLimit;
const SOURCE_WEB = 'web';
const SOURCE_CSV = 'csv';
const SOURCE_WEBHOOK = 'webhook';
protected $fillable = [
'user_id', 'ejaculated_date',
'note', 'geo_latitude', 'geo_longitude',
'is_private'
'note', 'geo_latitude', 'geo_longitude', 'link', 'source',
'is_private', 'is_too_sensitive', 'discard_elapsed_time',
'checkin_webhook_id'
];
protected $dates = [
'ejaculated_date'
];
public function user()
{
return $this->belongsTo('App\User');
}
public function tags()
{
return $this->belongsToMany('App\Tag')->withTimestamps();
}
public function textTags()
{
return implode(' ', $this->tags->map(function ($v) {
return $v->name;
})->all());
}
public function likes()
{
return $this->hasMany(Like::class);
}
public function scopeVisibleToTimeline(Builder $query)
{
return $query->whereIn('ejaculations.source', [Ejaculation::SOURCE_WEB, Ejaculation::SOURCE_WEBHOOK]);
}
public function scopeWithLikes(Builder $query)
{
if (Auth::check()) {
// TODO - このスコープを使うことでlikesが常に直近10件で絞られるのは汚染されすぎ感がある。別名を付与できないか
// - (ejaculation_id, user_id) でユニークなわけですが、is_liked はサブクエリ発行させるのとLeft JoinしてNULLかどうかで結果を見るのどっちがいいんでしょうね
return $query
->with([
'likes' => function ($query) {
$query->latest()->take(10);
},
'likes.user' => function ($query) {
$query->where('is_protected', false)
->where('private_likes', false)
->orWhere('id', Auth::id());
}
])
->withCount([
'likes',
'likes as is_liked' => function ($query) {
$query->where('user_id', Auth::id());
}
]);
} else {
return $query
->with([
'likes' => function ($query) {
$query->latest()->take(10);
},
'likes.user' => function ($query) {
$query->where('is_protected', false)
->where('private_likes', false);
}
])
->withCount('likes')
->addSelect(DB::raw('0 as is_liked'));
}
}
/**
* このチェックインと同じ情報を流用してチェックインするためのURLを生成
* @return string
*/
public function makeCheckinURL(): string
{
return route('checkin', [
'link' => $this->link,
'tags' => $this->textTags(),
'is_private' => $this->is_private,
'is_too_sensitive' => $this->is_too_sensitive,
]);
}
public function ejaculatedSpan(): string
{
if (array_key_exists('ejaculated_span', $this->attributes)) {
if ($this->ejaculated_span === null) {
return '精通';
}
if ($this->discard_elapsed_time) {
return '0日 0時間 0分'; // TODO: 気の効いたフレーズにする
}
return $this->ejaculated_span;
} else {
$previous = Ejaculation::select('ejaculated_date')
->where('user_id', $this->user_id)
->where('ejaculated_date', '<', $this->ejaculated_date)
->orderByDesc('ejaculated_date')
->first();
if ($previous === null) {
return '精通';
}
if ($this->discard_elapsed_time) {
return '0日 0時間 0分';
}
return $this->ejaculated_date->diff($previous->ejaculated_date)->format('%a日 %h時間 %i分');
}
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class LinkDiscovered
{
use Dispatchable, SerializesModels;
public $url;
/**
* Create a new event instance.
*
* @param string $url
*/
public function __construct(string $url)
{
$this->url = $url;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Exceptions;
use Illuminate\Support\Arr;
use Throwable;
class CsvImportException extends \RuntimeException
{
/** @var string[] */
private $errors;
/**
* CsvImportException constructor.
* @param string[] $errors
*/
public function __construct(...$errors)
{
parent::__construct(Arr::first($errors));
$this->errors = $errors;
}
/**
* @return string[]
*/
public function getErrors(): array
{
return $this->errors;
}
}

View File

@ -4,7 +4,10 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Handler extends ExceptionHandler
{
@ -20,18 +23,23 @@ class Handler extends ExceptionHandler
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
\App\MetadataResolver\ResolverCircuitBreakException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*
* @throws \Exception
*/
public function report(Exception $exception)
{
if (app()->bound('sentry') && $this->shouldReport($exception)) {
app('sentry')->captureException($exception);
}
parent::report($exception);
}
@ -40,7 +48,9 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Exception
*/
public function render($request, Exception $exception)
{
@ -62,4 +72,28 @@ class Handler extends ExceptionHandler
return redirect()->guest(route('login'));
}
protected function prepareException(Exception $e)
{
if (!config('app.debug') && $e instanceof ModelNotFoundException) {
return new NotFoundHttpException('Resource not found.', $e);
}
return parent::prepareException($e);
}
protected function prepareJsonResponse($request, Exception $e)
{
$status = $this->isHttpException($e) ? $e->getStatusCode() : 500;
return new JsonResponse(
[
'status' => $status,
'error' => $this->convertExceptionToArray($e),
],
$status,
$this->isHttpException($e) ? $e->getHeaders() : [],
JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
);
}
}

13
app/Facades/Formatter.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Formatter extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Utilities\Formatter::class;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class DashboardController extends Controller
{
public function index()
{
return view('admin.dashboard');
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\AdminInfoStoreRequest;
use App\Information;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
class InfoController extends Controller
{
public function index()
{
$informations = Information::query()
->select('id', 'category', 'pinned', 'title', 'created_at')
->orderByDesc('pinned')
->orderByDesc('created_at')
->paginate(20);
return view('admin.info.index')->with([
'informations' => $informations,
'categories' => Information::CATEGORIES
]);
}
public function create()
{
return view('admin.info.create')->with([
'categories' => Information::CATEGORIES
]);
}
public function store(AdminInfoStoreRequest $request)
{
$inputs = $request->all();
if (!$request->has('pinned')) {
$inputs['pinned'] = false;
}
$info = Information::create($inputs);
return redirect()->route('admin.info.edit', ['info' => $info])->with('status', 'お知らせを更新しました。');
}
public function edit(Information $info)
{
return view('admin.info.edit')->with([
'info' => $info,
'categories' => Information::CATEGORIES
]);
}
public function update(AdminInfoStoreRequest $request, Information $info)
{
$inputs = $request->all();
if (!$request->has('pinned')) {
$inputs['pinned'] = false;
}
$info->fill($inputs)->save();
return redirect()->route('admin.info.edit', ['info' => $info])->with('status', 'お知らせを更新しました。');
}
public function destroy(Information $info)
{
$info->delete();
return redirect()->route('admin.info')->with('status', 'お知らせを削除しました。');
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Controllers\Api;
use App\MetadataResolver\DeniedHostException;
use App\Services\MetadataResolveService;
use Illuminate\Http\Request;
class CardController
{
public function show(Request $request, MetadataResolveService $service)
{
$request->validate([
'url:required|url'
]);
try {
$metadata = $service->execute($request->input('url'));
} catch (DeniedHostException $e) {
abort(403, $e->getMessage());
}
$metadata->load('tags');
$response = response($metadata);
if (!config('app.debug')) {
$response = $response->setCache(['public' => true, 'max_age' => 86400]);
}
return $response;
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers\Api;
use App\Ejaculation;
use App\Http\Controllers\Controller;
use App\Like;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
class LikeController extends Controller
{
public function store(Request $request)
{
$request->validate([
'id' => 'required|integer|exists:ejaculations'
]);
$keys = [
'user_id' => Auth::id(),
'ejaculation_id' => $request->input('id')
];
$like = Like::query()->where($keys)->first();
if ($like) {
$data = [
'errors' => [
['message' => 'このチェックインはすでにいいね済です。']
],
'ejaculation' => $like->ejaculation
];
return response()->json($data, 409);
}
$like = Like::create($keys);
return [
'ejaculation' => $like->ejaculation
];
}
public function destroy($id)
{
Validator::make(compact('id'), [
'id' => 'required|integer'
])->validate();
$like = Like::query()->where([
'user_id' => Auth::id(),
'ejaculation_id' => $id
])->first();
if ($like === null) {
$ejaculation = Ejaculation::find($id);
$data = [
'errors' => [
['message' => 'このチェックインはいいねされていません。']
],
'ejaculation' => $ejaculation
];
return response()->json($data, 404);
}
$like->delete();
return [
'ejaculation' => $like->ejaculation
];
}
}

View File

@ -0,0 +1,105 @@
<?php
namespace App\Http\Controllers\Api;
use App\CheckinWebhook;
use App\Ejaculation;
use App\Events\LinkDiscovered;
use App\Http\Controllers\Controller;
use App\Http\Resources\EjaculationResource;
use App\Tag;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class WebhookController extends Controller
{
public function checkin(CheckinWebhook $webhook, Request $request)
{
if (!$webhook->isAvailable()) {
return response()->json([
'status' => 404,
'error' => [
'message' => 'The webhook is unavailable'
]
], 404);
}
$validator = Validator::make($request->all(), [
'checked_in_at' => 'nullable|date|after_or_equal:2000-01-01 00:00:00|before_or_equal:2099-12-31 23:59:59',
'note' => 'nullable|string|max:500',
'link' => 'nullable|url|max:2000',
'tags' => 'nullable|array',
'tags.*' => ['string', 'not_regex:/[\s\r\n]/u', 'max:255'],
'is_private' => 'nullable|boolean',
'is_too_sensitive' => 'nullable|boolean',
'discard_elapsed_time' => 'nullable|boolean',
], [
'tags.*.not_regex' => 'The :attribute cannot contain spaces, tabs and newlines.'
]);
try {
$inputs = $validator->validate();
} catch (ValidationException $e) {
return response()->json([
'status' => 422,
'error' => [
'message' => 'Validation failed',
'violations' => $validator->errors()->all(),
]
], 422);
}
$ejaculatedDate = empty($inputs['checked_in_at']) ? now() : new Carbon($inputs['checked_in_at']);
$ejaculatedDate = $ejaculatedDate->setTimezone(date_default_timezone_get())->startOfMinute();
if (Ejaculation::where(['user_id' => $webhook->user_id, 'ejaculated_date' => $ejaculatedDate])->count()) {
return response()->json([
'status' => 422,
'error' => [
'message' => 'Checkin already exists in this time',
]
], 422);
}
$ejaculation = DB::transaction(function () use ($inputs, $webhook, $ejaculatedDate) {
$ejaculation = Ejaculation::create([
'user_id' => $webhook->user_id,
'ejaculated_date' => $ejaculatedDate,
'note' => $inputs['note'] ?? '',
'link' => $inputs['link'] ?? '',
'source' => Ejaculation::SOURCE_WEBHOOK,
'is_private' => (bool)($inputs['is_private'] ?? false),
'is_too_sensitive' => (bool)($inputs['is_too_sensitive'] ?? false),
'discard_elapsed_time' => (bool)($inputs['discard_elapsed_time'] ?? false),
'checkin_webhook_id' => $webhook->id
]);
$tagIds = [];
if (!empty($inputs['tags'])) {
foreach ($inputs['tags'] as $tag) {
$tag = trim($tag);
if ($tag === '') {
continue;
}
$tag = Tag::firstOrCreate(['name' => $tag]);
$tagIds[] = $tag->id;
}
}
$ejaculation->tags()->sync($tagIds);
return $ejaculation;
});
if (!empty($ejaculation->link)) {
event(new LinkDiscovered($ejaculation->link));
}
return response()->json([
'status' => 200,
'checkin' => new EjaculationResource($ejaculation)
]);
}
}

View File

@ -2,10 +2,11 @@
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use App\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
@ -47,11 +48,20 @@ class RegisterController extends Controller
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|regex:/^[a-zA-Z0-9_-]+$/u|max:15|unique:users',
$rules = [
'name' => 'required|string|regex:/^[a-zA-Z0-9_-]+$/u|max:15|unique:users|unique:deactivated_users',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
],
'password' => 'required|string|min:8|confirmed'
];
// reCAPTCHAのキーが設定されている場合、判定を有効化
if (!empty(config('captcha.secret'))) {
$rules['g-recaptcha-response'] = 'required|captcha';
}
return Validator::make(
$data,
$rules,
['name.regex' => 'ユーザー名には半角英数字とアンダーバー、ハイフンのみ使用できます。'],
['name' => 'ユーザー名']
);
@ -69,7 +79,7 @@ class RegisterController extends Controller
'name' => $data['name'],
'display_name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'password' => Hash::make($data['password']),
'is_protected' => $data['is_protected'] ?? false,
'accept_analytics' => $data['accept_analytics'] ?? false
]);

View File

@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/
use VerifiesEmails;
/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}

View File

@ -2,10 +2,10 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{

View File

@ -2,59 +2,240 @@
namespace App\Http\Controllers;
use Validator;
use App\Ejaculation;
use App\Events\LinkDiscovered;
use App\Tag;
use App\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Validator;
class EjaculationController extends Controller
{
public function create()
public function create(Request $request)
{
return view('ejaculation.checkin');
$tags = old('tags') ?? $request->input('tags', '');
if (!empty($tags)) {
$tags = explode(' ', $tags);
}
$errors = $request->session()->get('errors');
$initialState = [
'mode' => 'create',
'fields' => [
'date' => old('date') ?? $request->input('date', date('Y/m/d')),
'time' => old('time') ?? $request->input('time', date('H:i')),
'link' => old('link') ?? $request->input('link', ''),
'tags' => $tags,
'note' => old('note') ?? $request->input('note', ''),
'is_private' => old('is_private') ?? $request->input('is_private', 0) == 1,
'is_too_sensitive' => old('is_too_sensitive') ?? $request->input('is_too_sensitive', 0) == 1,
'is_realtime' => old('is_realtime', true),
'discard_elapsed_time' => old('discard_elapsed_time') ?? $request->input('discard_elapsed_time') == 1,
],
'errors' => isset($errors) ? $errors->getMessages() : null
];
return view('ejaculation.checkin')->with('initialState', $initialState);
}
public function store(Request $request)
{
Validator::make($request->all(), [
$inputs = $request->all();
$validator = Validator::make($inputs, [
'date' => 'required_without:is_realtime|date_format:Y/m/d',
'time' => 'required_without:is_realtime|date_format:H:i',
'note' => 'nullable|string|max:500',
'link' => 'nullable|url|max:2000',
'tags' => 'nullable|string',
])->after(function ($validator) use ($request, $inputs) {
// 日時の重複チェック
if (!$validator->errors()->hasAny(['date', 'time'])) {
if (isset($inputs['date']) && isset($inputs['time'])) {
$dt = Carbon::createFromFormat('Y/m/d H:i', $inputs['date'] . ' ' . $inputs['time']);
} else {
$dt = now();
}
$dt = $dt->startOfMinute();
if (Ejaculation::where(['user_id' => Auth::id(), 'ejaculated_date' => $dt])->count()) {
$validator->errors()->add('datetime', '既にこの日時にチェックインしているため、登録できません。');
}
}
});
if ($validator->fails()) {
return redirect()->route('checkin')
->withErrors($validator)
->withInput(array_merge(['is_realtime' => false], $request->input()));
}
$ejaculation = DB::transaction(function () use ($request, $inputs) {
if (isset($inputs['date']) && isset($inputs['time'])) {
$ejaculatedDate = Carbon::createFromFormat('Y/m/d H:i', $inputs['date'] . ' ' . $inputs['time']);
} else {
$ejaculatedDate = now();
}
$ejaculatedDate = $ejaculatedDate->startOfMinute();
$ejaculation = Ejaculation::create([
'user_id' => Auth::id(),
'ejaculated_date' => $ejaculatedDate,
'note' => $inputs['note'] ?? '',
'link' => $inputs['link'] ?? '',
'source' => Ejaculation::SOURCE_WEB,
'is_private' => $request->has('is_private') ?? false,
'is_too_sensitive' => $request->has('is_too_sensitive') ?? false,
'discard_elapsed_time' => $request->has('discard_elapsed_time') ?? false,
]);
$tagIds = [];
if (!empty($inputs['tags'])) {
$tags = explode(' ', $inputs['tags']);
foreach ($tags as $tag) {
if ($tag === '') {
continue;
}
$tag = Tag::firstOrCreate(['name' => $tag]);
$tagIds[] = $tag->id;
}
}
$ejaculation->tags()->sync($tagIds);
return $ejaculation;
});
if (!empty($ejaculation->link)) {
event(new LinkDiscovered($ejaculation->link));
}
return redirect()->route('checkin.show', ['id' => $ejaculation->id])->with('status', 'チェックインしました!');
}
public function show($id)
{
$ejaculation = Ejaculation::where('id', $id)
->withLikes()
->firstOrFail();
$user = User::findOrFail($ejaculation->user_id);
return view('ejaculation.show')->with(compact('user', 'ejaculation'));
}
public function edit(Request $request, $id)
{
$ejaculation = Ejaculation::findOrFail($id);
$this->authorize('edit', $ejaculation);
if (old('tags') === null) {
$tags = $ejaculation->tags->pluck('name');
} else {
$tags = old('tags');
if (!empty($tags)) {
$tags = explode(' ', $tags);
}
}
$errors = $request->session()->get('errors');
$initialState = [
'mode' => 'update',
'fields' => [
'date' => old('date') ?? $ejaculation->ejaculated_date->format('Y/m/d'),
'time' => old('time') ?? $ejaculation->ejaculated_date->format('H:i'),
'link' => old('link') ?? $ejaculation->link,
'tags' => $tags,
'note' => old('note') ?? $ejaculation->note,
'is_private' => is_bool(old('is_private')) ? old('is_private') : $ejaculation->is_private,
'is_too_sensitive' => is_bool(old('is_too_sensitive')) ? old('is_too_sensitive') : $ejaculation->is_too_sensitive,
'discard_elapsed_time' => is_bool(old('discard_elapsed_time')) ? old('discard_elapsed_time') : $ejaculation->discard_elapsed_time,
],
'errors' => isset($errors) ? $errors->getMessages() : null
];
return view('ejaculation.edit')->with(compact('ejaculation', 'initialState'));
}
public function update(Request $request, $id)
{
$ejaculation = Ejaculation::findOrFail($id);
$this->authorize('edit', $ejaculation);
$inputs = $request->all();
$validator = Validator::make($inputs, [
'date' => 'required|date_format:Y/m/d',
'time' => 'required|date_format:H:i',
'note' => 'nullable|string|max:500',
])->after(function ($validator) use ($request) {
'link' => 'nullable|url|max:2000',
'tags' => 'nullable|string',
])->after(function ($validator) use ($id, $request, $inputs) {
// 日時の重複チェック
$dt = $request->input('date') . ' ' . $request->input('time');
if (Ejaculation::where(['user_id' => Auth::id(), 'ejaculated_date' => $dt])->count()) {
$validator->errors()->add('datetime', '既にこの日時にチェックインしているため、登録できません。');
if (!$validator->errors()->hasAny(['date', 'time'])) {
$dt = $inputs['date'] . ' ' . $inputs['time'];
if (Ejaculation::where(['user_id' => Auth::id(), 'ejaculated_date' => $dt])->where('id', '<>', $id)->count()) {
$validator->errors()->add('datetime', '既にこの日時にチェックインしているため、登録できません。');
}
}
})->validate();
});
Ejaculation::create([
'user_id' => Auth::id(),
'ejaculated_date' => $request->input('date') . ' ' . $request->input('time'),
'note' => $request->input('note') ?? '',
'is_private' => $request->has('is_private') ?? false
]);
if ($validator->fails()) {
return redirect()->route('checkin.edit', ['id' => $id])->withErrors($validator)->withInput();
}
return redirect()->route('home')->with('status', 'チェックインしました!');
DB::transaction(function () use ($ejaculation, $request, $inputs) {
$ejaculation->fill([
'ejaculated_date' => Carbon::createFromFormat('Y/m/d H:i', $inputs['date'] . ' ' . $inputs['time']),
'note' => $inputs['note'] ?? '',
'link' => $inputs['link'] ?? '',
'is_private' => $request->has('is_private') ?? false,
'is_too_sensitive' => $request->has('is_too_sensitive') ?? false,
'discard_elapsed_time' => $request->has('discard_elapsed_time') ?? false,
])->save();
$tagIds = [];
if (!empty($inputs['tags'])) {
$tags = explode(' ', $inputs['tags']);
foreach ($tags as $tag) {
if ($tag === '') {
continue;
}
$tag = Tag::firstOrCreate(['name' => $tag]);
$tagIds[] = $tag->id;
}
}
$ejaculation->tags()->sync($tagIds);
});
if (!empty($ejaculation->link)) {
event(new LinkDiscovered($ejaculation->link));
}
return redirect()->route('checkin.show', ['id' => $ejaculation->id])->with('status', 'チェックインを修正しました!');
}
public function show()
public function destroy($id)
{
// TODO: not implemented
$ejaculation = Ejaculation::findOrFail($id);
$this->authorize('edit', $ejaculation);
$user = User::findOrFail($ejaculation->user_id);
DB::transaction(function () use ($ejaculation) {
$ejaculation->tags()->detach();
$ejaculation->delete();
});
return redirect()->route('user.profile', ['name' => $user->name])->with('status', '削除しました。');
}
public function edit()
public function tools()
{
// TODO: not implemented
return view('ejaculation.tools');
}
public function update()
{
// TODO: not implemented
}
public function destroy()
{
// TODO: not implemented
}
}
}

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Ejaculation;
use App\Information;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@ -26,54 +27,57 @@ class HomeController extends Controller
*/
public function index()
{
if (Auth::check()) {
$ejaculations = Ejaculation::select(DB::raw(<<<'SQL'
to_char(ejaculated_date, 'YYYY/MM/DD HH24:MI') AS ejaculated_date,
note,
is_private,
to_char(lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC), 'YYYY/MM/DD HH24:MI') AS before_date,
to_char(ejaculated_date - (lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC)), 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
SQL
))
->where(['user_id' => Auth::id()])
->orderBy('ejaculated_date', 'desc')
->limit(9)
->get();
$informations = Information::query()
->select('id', 'category', 'pinned', 'title', 'created_at')
->orderByDesc('pinned')
->orderByDesc('created_at')
->take(3)
->get();
$categories = Information::CATEGORIES;
// 現在のオナ禁セッションの経過時間
if (count($ejaculations) > 0) {
$currentSession = Carbon::parse($ejaculations[0]['ejaculated_date'])
->diff(Carbon::now())
->format('%d日 %h時間 %i分');
} else {
$currentSession = null;
if (Auth::check()) {
// チェックイン動向グラフ用のデータ取得
$groupByDay = Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
count(*) AS "count"
SQL
))
->join('users', function ($join) {
$join->on('users.id', '=', 'ejaculations.user_id')
->where('users.accept_analytics', true);
})
->where('ejaculated_date', '>=', now()->subDays(30))
->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
->get()
->mapWithKeys(function ($item) {
return [$item['date'] => $item['count']];
});
$globalEjaculationCounts = [];
$day = Carbon::now()->subDays(29);
for ($i = 0; $i < 30; $i++) {
$globalEjaculationCounts[$day->format('Y/m/d') . ' の総チェックイン数'] = $groupByDay[$day->format('Y/m/d')] ?? 0;
$day->addDay();
}
// 概況欄のデータ取得
$summary = DB::select(<<<'SQL'
SELECT
to_char(avg(span), 'FMDDD日 FMHH24時間 FMMI分') AS average,
to_char(max(span), 'FMDDD日 FMHH24時間 FMMI分') AS longest,
to_char(min(span), 'FMDDD日 FMHH24時間 FMMI分') AS shortest,
to_char(sum(span), 'FMDDD日 FMHH24時間 FMMI分') AS total_times,
count(*) AS total_checkins
FROM
(
SELECT
ejaculated_date - lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC) AS span
FROM
ejaculations
WHERE
user_id = :user_id
ORDER BY
ejaculated_date DESC
) AS temp
SQL
, ['user_id' => Auth::id()]);
// お惣菜コーナー用のデータ取得
$publicLinkedEjaculations = Ejaculation::join('users', 'users.id', '=', 'ejaculations.user_id')
->where('users.is_protected', false)
->where('ejaculations.is_private', false)
->where('ejaculations.link', '<>', '')
->where('ejaculations.ejaculated_date', '<=', Carbon::now())
->orderBy('ejaculations.ejaculated_date', 'desc')
->select('ejaculations.*')
->with('user', 'tags')
->withLikes()
->visibleToTimeline()
->take(21)
->get();
return view('home')->with(compact('ejaculations', 'currentSession', 'summary'));
return view('home')->with(compact('informations', 'categories', 'globalEjaculationCounts', 'publicLinkedEjaculations'));
} else {
return view('guest');
return view('guest')->with(compact('informations', 'categories'));
}
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Http\Controllers;
use App\Information;
use Illuminate\Http\Request;
class InfoController extends Controller
{
public function index()
{
$informations = Information::query()
->select('id', 'category', 'pinned', 'title', 'created_at')
->orderByDesc('pinned')
->orderByDesc('created_at')
->paginate(20);
return view('info.index')->with([
'informations' => $informations,
'categories' => Information::CATEGORIES
]);
}
public function show($id)
{
$information = Information::findOrFail($id);
return view('info.show')->with([
'info' => $information,
'category' => Information::CATEGORIES[$information->category]
]);
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace App\Http\Controllers;
use App\Ejaculation;
use App\Tag;
use App\Utilities\Formatter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class SearchController extends Controller
{
/** @var Formatter */
private $formatter;
public function __construct(Formatter $formatter)
{
$this->formatter = $formatter;
}
public function index(Request $request)
{
$inputs = $request->validate([
'q' => 'required'
]);
$q = $this->normalizeQuery($inputs['q']);
$results = Ejaculation::query()
->whereHas('tags', function ($query) use ($q) {
$query->where('normalized_name', 'like', "%{$q}%");
})
->whereHas('user', function ($query) {
$query->where('is_protected', false);
if (Auth::check()) {
$query->orWhere('id', Auth::id());
}
})
->where('is_private', false)
->orderBy('ejaculated_date', 'desc')
->with(['user', 'tags'])
->withLikes()
->paginate(20)
->appends($inputs);
return view('search.index')->with(compact('inputs', 'results'));
}
public function relatedTag(Request $request)
{
$inputs = $request->validate([
'q' => 'required'
]);
$q = $this->normalizeQuery($inputs['q']);
$results = Tag::query()
->where('normalized_name', 'like', "%{$q}%")
->paginate(50)
->appends($inputs);
return view('search.relatedTag')->with(compact('inputs', 'results'));
}
private function normalizeQuery(string $query): string
{
return $this->formatter->normalizeTagName($query);
}
}

View File

@ -0,0 +1,242 @@
<?php
namespace App\Http\Controllers;
use App\CheckinWebhook;
use App\DeactivatedUser;
use App\Ejaculation;
use App\Exceptions\CsvImportException;
use App\Services\CheckinCsvExporter;
use App\Services\CheckinCsvImporter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
class SettingController extends Controller
{
public function profile()
{
return view('setting.profile');
}
public function updateProfile(Request $request)
{
$inputs = $request->all();
$validator = Validator::make($inputs, [
'display_name' => 'required|string|max:20',
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore(Auth::user()->email, 'email')
],
'bio' => 'nullable|string|max:160',
'url' => 'nullable|url|max:2000'
], [], [
'display_name' => '名前',
'email' => 'メールアドレス',
'bio' => '自己紹介',
'url' => 'URL'
]);
if ($validator->fails()) {
return redirect()->route('setting')->withErrors($validator)->withInput();
}
$user = Auth::user();
$user->display_name = $inputs['display_name'];
$user->email = $inputs['email'];
$user->bio = $inputs['bio'] ?? '';
$user->url = $inputs['url'] ?? '';
$user->save();
return redirect()->route('setting')->with('status', 'プロフィールを更新しました。');
}
public function privacy()
{
return view('setting.privacy');
}
public function updatePrivacy(Request $request)
{
$inputs = $request->all(['is_protected', 'accept_analytics', 'private_likes']);
$user = Auth::user();
$user->is_protected = $inputs['is_protected'] ?? false;
$user->accept_analytics = $inputs['accept_analytics'] ?? false;
$user->private_likes = $inputs['private_likes'] ?? false;
$user->save();
return redirect()->route('setting.privacy')->with('status', 'プライバシー設定を更新しました。');
}
public function webhooks()
{
$webhooks = Auth::user()->checkinWebhooks;
$webhooksLimit = CheckinWebhook::PER_USER_LIMIT;
return view('setting.webhooks')->with(compact('webhooks', 'webhooksLimit'));
}
public function storeWebhooks(Request $request)
{
$validated = $request->validate([
'name' => [
'required',
'string',
'max:255',
Rule::unique('checkin_webhooks', 'name')->where(function ($query) {
return $query->where('user_id', Auth::id());
})
]
], [], [
'name' => '名前'
]);
if (Auth::user()->checkinWebhooks()->count() >= CheckinWebhook::PER_USER_LIMIT) {
return redirect()->route('setting.webhooks')
->with('status', CheckinWebhook::PER_USER_LIMIT . '件以上のWebhookを作成することはできません。');
}
Auth::user()->checkinWebhooks()->create($validated);
return redirect()->route('setting.webhooks')->with('status', '作成しました。');
}
public function destroyWebhooks(CheckinWebhook $webhook)
{
$webhook->delete();
return redirect()->route('setting.webhooks')->with('status', '削除しました。');
}
public function import()
{
return view('setting.import');
}
public function storeImport(Request $request)
{
$validated = $request->validate([
'file' => 'required|file'
], [], [
'file' => 'ファイル'
]);
$file = $request->file('file');
if (!$file->isValid()) {
return redirect()->route('setting.import')->withErrors(['file' => 'ファイルのアップロードに失敗しました。']);
}
try {
set_time_limit(0);
$importer = new CheckinCsvImporter(Auth::user(), $file->path());
$imported = $importer->execute();
return redirect()->route('setting.import')->with('status', "{$imported}件のインポートに性交しました。");
} catch (CsvImportException $e) {
return redirect()->route('setting.import')->with('import_errors', $e->getErrors());
}
}
public function destroyImport()
{
Auth::user()
->ejaculations()
->where('ejaculations.source', Ejaculation::SOURCE_CSV)
->delete();
return redirect()->route('setting.import')->with('status', '削除が完了しました。');
}
public function export()
{
return view('setting.export');
}
public function exportToCsv(Request $request)
{
$validated = $request->validate([
'charset' => ['required', Rule::in(['utf8', 'sjis'])]
]);
$charsets = [
'utf8' => 'UTF-8',
'sjis' => 'SJIS-win'
];
$filename = tempnam(sys_get_temp_dir(), 'tissue_export_tmp_');
try {
// 気休め
set_time_limit(0);
$exporter = new CheckinCsvExporter(Auth::user(), $filename, $charsets[$validated['charset']]);
$exporter->execute();
} catch (\Throwable $e) {
unlink($filename);
throw $e;
}
return response()
->download($filename, 'TissueCheckin_' . date('Y-m-d_H-i-s') . '.csv')
->deleteFileAfterSend(true);
}
public function deactivate()
{
return view('setting.deactivate');
}
public function destroyUser(Request $request)
{
// パスワードチェック
$validated = $request->validate([
'password' => 'required|string'
]);
if (!Hash::check($validated['password'], Auth::user()->getAuthPassword())) {
throw ValidationException::withMessages([
'password' => 'パスワードが正しくありません。'
]);
}
// データの削除
set_time_limit(0);
DB::transaction(function () {
$user = Auth::user();
// 関連レコードの削除
// TODO: 別にDELETE文相当のクエリを一発発行するだけでもいい
foreach ($user->ejaculations as $ejaculation) {
$ejaculation->delete();
}
foreach ($user->likes as $like) {
$like->delete();
}
// 先にログアウトしないとユーザーは消せない
Auth::logout();
// ユーザーの削除
$user->delete();
// ユーザー名履歴に追記
DeactivatedUser::create(['name' => $user->name]);
});
return view('setting.deactivated');
}
// ( ◠‿◠ )☛ここに気づいたか・・・消えてもらう ▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂うわあああああああ
// public function password()
// {
// abort(501);
// }
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Http\Controllers;
use App\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class TagController extends Controller
{
public function index()
{
$tags = Tag::select(DB::raw(
<<<'SQL'
tags.name,
count(*) AS "checkins_count"
SQL
))
->join('ejaculation_tag', 'tags.id', '=', 'ejaculation_tag.tag_id')
->join('ejaculations', 'ejaculations.id', '=', 'ejaculation_tag.ejaculation_id')
->join('users', 'users.id', '=', 'ejaculations.user_id')
->where('ejaculations.is_private', false)
->where(function ($query) {
$query->where('users.is_protected', false);
if (Auth::check()) {
$query->orWhere('users.id', Auth::id());
}
})
->groupBy('tags.name')
->orderByDesc('checkins_count')
->orderBy('tags.name')
->paginate(100);
return view('tag.index', compact('tags'));
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers;
use App\Ejaculation;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
class TimelineController extends Controller
{
public function showPublic()
{
$ejaculations = Ejaculation::join('users', 'users.id', '=', 'ejaculations.user_id')
->where('users.is_protected', false)
->where('ejaculations.is_private', false)
->where('ejaculations.link', '<>', '')
->where('ejaculations.ejaculated_date', '<=', Carbon::now())
->orderBy('ejaculations.ejaculated_date', 'desc')
->select('ejaculations.*')
->with('user', 'tags')
->withLikes()
->visibleToTimeline()
->paginate(21);
return view('timeline.public')->with(compact('ejaculations'));
}
}

View File

@ -5,13 +5,18 @@ namespace App\Http\Controllers;
use App\Ejaculation;
use App\User;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Validator;
class UserController extends Controller
{
//
public function redirectMypage()
{
return redirect()->route('user.profile', ['name' => auth()->user()->name]);
}
public function profile($name)
{
@ -21,52 +26,295 @@ class UserController extends Controller
}
// チェックインの取得
$query = Ejaculation::select(DB::raw(<<<'SQL'
to_char(ejaculated_date, 'YYYY/MM/DD HH24:MI') AS ejaculated_date,
$query = Ejaculation::select(DB::raw(
<<<'SQL'
ejaculations.id,
ejaculated_date,
note,
is_private,
to_char(lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC), 'YYYY/MM/DD HH24:MI') AS before_date,
to_char(ejaculated_date - (lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC)), 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
is_too_sensitive,
link,
source,
discard_elapsed_time,
to_char(before_dates.before_date, 'YYYY/MM/DD HH24:MI') AS before_date,
to_char(ejaculated_date - before_dates.before_date, 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
SQL
))
->joinSub($this->queryBeforeEjaculatedDates(), 'before_dates', 'before_dates.id', '=', 'ejaculations.id')
->where('user_id', $user->id);
if (!Auth::check() || $user->id !== Auth::id()) {
$query = $query->where('is_private', false);
}
$ejaculations = $query->orderBy('ejaculated_date', 'desc')
->with('tags')
->withLikes()
->paginate(20);
// 現在のオナ禁セッションの経過時間
if (count($ejaculations) > 0) {
$currentSession = Carbon::parse($ejaculations[0]['ejaculated_date'])
->diff(Carbon::now())
->format('%d日 %h時間 %i分');
} else {
$currentSession = null;
// よく使っているタグ
$tagsQuery = DB::table('ejaculations')
->join('ejaculation_tag', 'ejaculations.id', '=', 'ejaculation_tag.ejaculation_id')
->join('tags', 'ejaculation_tag.tag_id', '=', 'tags.id')
->selectRaw('tags.name, count(*) as count')
->where('ejaculations.user_id', $user->id);
if (!Auth::check() || $user->id !== Auth::id()) {
$tagsQuery = $tagsQuery->where('ejaculations.is_private', false);
}
$tags = $tagsQuery->groupBy('tags.name')
->orderBy('count', 'desc')
->limit(10)
->get();
// シコ草
$countByDayQuery = $this->countEjaculationByDay($user)
->where('ejaculated_date', '>=', now()->startOfMonth()->subMonths(9))
->where('ejaculated_date', '<', now()->addMonth()->startOfMonth())
->get();
$countByDay = [];
foreach ($countByDayQuery as $data) {
$date = Carbon::createFromFormat('Y/m/d', $data->date);
$countByDay[$date->timestamp] = $data->count;
}
// 概況欄のデータ取得
$summary = DB::select(<<<'SQL'
SELECT
to_char(avg(span), 'FMDDD日 FMHH24時間 FMMI分') AS average,
to_char(max(span), 'FMDDD日 FMHH24時間 FMMI分') AS longest,
to_char(min(span), 'FMDDD日 FMHH24時間 FMMI分') AS shortest,
to_char(sum(span), 'FMDDD日 FMHH24時間 FMMI分') AS total_times,
count(*) AS total_checkins
FROM
(
SELECT
ejaculated_date - lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC) AS span
FROM
ejaculations
WHERE
user_id = :user_id
ORDER BY
ejaculated_date DESC
) AS temp
SQL
, ['user_id' => $user->id]);
return view('user.profile')->with(compact('user', 'ejaculations', 'tags', 'countByDay'));
}
return view('user.profile')->with(compact('user', 'ejaculations', 'currentSession', 'summary'));
public function stats($name)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
}
$availableMonths = $this->makeStatsAvailableMonths($user);
$graphData = $this->makeGraphData($user);
return view('user.stats.index')->with(compact('user', 'graphData', 'availableMonths'));
}
public function statsYearly($name, $year)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
}
$validator = Validator::make(compact('year'), [
'year' => 'required|date_format:Y'
]);
if ($validator->fails()) {
return redirect()->route('user.stats', compact('name'));
}
$availableMonths = $this->makeStatsAvailableMonths($user);
if (!isset($availableMonths[$year])) {
return redirect()->route('user.stats', compact('name'));
}
$graphData = $this->makeGraphData(
$user,
Carbon::createFromDate($year, 1, 1, config('app.timezone'))->startOfDay(),
Carbon::createFromDate($year, 1, 1, config('app.timezone'))->addYear()->startOfDay()
);
return view('user.stats.yearly')
->with(compact('user', 'graphData', 'availableMonths'))
->with('currentYear', (int) $year);
}
public function statsMonthly($name, $year, $month)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
}
$validator = Validator::make(compact('year', 'month'), [
'year' => 'required|date_format:Y',
'month' => 'required|date_format:m'
]);
if ($validator->fails()) {
return redirect()->route('user.stats.yearly', compact('name', 'year'));
}
$availableMonths = $this->makeStatsAvailableMonths($user);
if (!isset($availableMonths[$year]) || !in_array($month, $availableMonths[$year], false)) {
return redirect()->route('user.stats.yearly', compact('name', 'year'));
}
$graphData = $this->makeGraphData(
$user,
Carbon::createFromDate($year, $month, 1, config('app.timezone'))->startOfDay(),
Carbon::createFromDate($year, $month, 1, config('app.timezone'))->addMonth()->startOfDay()
);
return view('user.stats.monthly')
->with(compact('user', 'graphData', 'availableMonths'))
->with('currentYear', (int) $year)
->with('currentMonth', (int) $month);
}
public function okazu($name)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
}
// チェックインの取得
$query = Ejaculation::select(DB::raw(
<<<'SQL'
ejaculations.id,
ejaculated_date,
note,
is_private,
is_too_sensitive,
link,
source,
discard_elapsed_time,
to_char(before_dates.before_date, 'YYYY/MM/DD HH24:MI') AS before_date,
to_char(ejaculated_date - before_dates.before_date, 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
SQL
))
->joinSub($this->queryBeforeEjaculatedDates(), 'before_dates', 'before_dates.id', '=', 'ejaculations.id')
->where('user_id', $user->id)
->where('link', '<>', '');
if (!Auth::check() || $user->id !== Auth::id()) {
$query = $query->where('is_private', false);
}
$ejaculations = $query->orderBy('ejaculated_date', 'desc')
->with('tags')
->withLikes()
->paginate(20);
return view('user.profile')->with(compact('user', 'ejaculations'));
}
public function likes($name)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
}
$likes = $user->likes()
->orderBy('created_at', 'desc')
->with('ejaculation.user', 'ejaculation.tags')
->whereHas('ejaculation', function ($query) {
$query->where('user_id', Auth::id())
->orWhere('is_private', false);
})
->paginate(20);
return view('user.likes')->with(compact('user', 'likes'));
}
private function makeStatsAvailableMonths(User $user): array
{
$availableMonths = [];
$oldest = $user->ejaculations()->orderBy('ejaculated_date')->first();
if (isset($oldest)) {
$oldestMonth = $oldest->ejaculated_date->startOfMonth();
$currentMonth = now()->startOfMonth();
for ($month = $currentMonth; $oldestMonth <= $currentMonth; $month = $month->subMonth()) {
if (!isset($availableMonths[$month->year])) {
$availableMonths[$month->year] = [];
}
$availableMonths[$month->year][] = $month->month;
}
}
return $availableMonths;
}
private function makeGraphData(User $user, CarbonInterface $dateSince = null, CarbonInterface $dateUntil = null): array
{
if ($dateUntil === null) {
$dateUntil = now()->addMonth()->startOfMonth();
}
$dateCondition = [
['ejaculated_date', '<', $dateUntil],
];
if ($dateSince !== null) {
$dateCondition[] = ['ejaculated_date', '>=', $dateSince];
}
$groupByDay = $this->countEjaculationByDay($user)
->where($dateCondition)
->get();
$groupByHour = Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'HH24') AS "hour",
count(*) AS "count"
SQL
))
->where('user_id', $user->id)
->where($dateCondition)
->groupBy(DB::raw("to_char(ejaculated_date, 'HH24')"))
->orderBy(DB::raw('1'))
->get();
$dailySum = [];
$monthlySum = [];
$yearlySum = [];
$dowSum = array_fill(0, 7, 0);
$hourlySum = array_fill(0, 24, 0);
// 年間グラフ用の配列初期化
if ($groupByDay->first() !== null) {
$year = Carbon::createFromFormat('Y/m/d', $groupByDay->first()->date)->year;
$currentYear = date('Y');
for (; $year <= $currentYear; $year++) {
$yearlySum[$year] = 0;
}
}
foreach ($groupByDay as $data) {
$date = Carbon::createFromFormat('Y/m/d', $data->date);
$yearAndMonth = $date->format('Y/m');
$dailySum[$date->timestamp] = $data->count;
$yearlySum[$date->year] += $data->count;
$dowSum[$date->dayOfWeek] += $data->count;
$monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count;
}
foreach ($groupByHour as $data) {
$hour = (int)$data->hour;
$hourlySum[$hour] += $data->count;
}
return [
'dailySum' => $dailySum,
'dowSum' => $dowSum,
'monthlySum' => $monthlySum,
'yearlyKey' => array_keys($yearlySum),
'yearlySum' => array_values($yearlySum),
'hourlyKey' => array_keys($hourlySum),
'hourlySum' => array_values($hourlySum),
];
}
private function countEjaculationByDay(User $user)
{
return Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
count(*) AS "count"
SQL
))
->where('user_id', $user->id)
->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"));
}
private function queryBeforeEjaculatedDates()
{
return DB::table('ejaculations')->selectRaw(
<<<'SQL'
id,
(select ejaculated_date from ejaculations e2 where e2.ejaculated_date < ejaculations.ejaculated_date and e2.user_id = ejaculations.user_id order by e2.ejaculated_date desc limit 1) AS before_date
SQL
);
}
}

View File

@ -14,7 +14,8 @@ class Kernel extends HttpKernel
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
@ -34,12 +35,20 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\NormalizeLineEnding::class,
],
'api' => [
'throttle:60,1',
'bindings',
\App\Http\Middleware\EnforceJson::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'stateful' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
]
];
/**
@ -50,11 +59,33 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* @var array
*/
protected $middlewarePriority = [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Authenticate::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use Closure;
/**
* Request headerに Accept: application/json を上書きする。APIエンドポイント用。
*/
class EnforceJson
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
return $next($request);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Middleware;
use Closure;
/**
* リクエスト内の改行コードを正規化する。
* @package App\Http\Middleware
*/
class NormalizeLineEnding
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$newInput = [];
foreach ($request->input() as $key => $value) {
$newInput[$key] = str_replace(["\r\n", "\r"], "\n", $value);
}
$request->replace($newInput);
return $next($request);
}
}

View File

@ -18,7 +18,7 @@ class RedirectIfAuthenticated
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home');
return redirect()->route('home');
}
return $next($request);

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array|string
*/
protected $proxies = '**';
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

View File

@ -6,6 +6,13 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*

View File

@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use App\Information;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class AdminInfoStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'category' => ['required', Rule::in(array_keys(Information::CATEGORIES))],
'pinned' => 'nullable|boolean',
'title' => 'required|string|max:255',
'content' => 'required|string|max:10000'
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class EjaculationResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'checked_in_at' => $this->ejaculated_date->format(\DateTime::ATOM),
'note' => $this->note,
'link' => $this->link,
'tags' => $this->tags->pluck('name'),
'source' => $this->source,
'is_private' => $this->is_private,
'is_too_sensitive' => $this->is_too_sensitive,
];
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace App\Http\ViewComposers;
use App\Ejaculation;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class ProfileStatsComposer
{
public function __construct()
{
}
public function compose(View $view)
{
// user変数に値が設定されてない場合は落とす
if (!$view->offsetExists('user')) {
throw new \LogicException('View data "user" was not exist.');
}
/** @var \App\User $user */
$user = $view->offsetGet('user');
// 現在のオナ禁セッションの経過時間
$latestEjaculation = Ejaculation::select('ejaculated_date')
->where('user_id', $user->id)
->orderByDesc('ejaculated_date')
->first();
if (!empty($latestEjaculation)) {
$currentSession = $latestEjaculation->ejaculated_date
->diff(Carbon::now())
->format('%a日 %h時間 %i分');
} else {
$currentSession = null;
}
// 概況欄のデータ取得
$average = 0;
$divisor = 0;
$averageSources = DB::select(<<<'SQL'
SELECT
extract(epoch from ejaculated_date - lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC)) AS span,
discard_elapsed_time
FROM
ejaculations
WHERE
user_id = :user_id
ORDER BY
ejaculated_date DESC
LIMIT
30
SQL
, ['user_id' => $user->id]);
foreach ($averageSources as $item) {
// 経過時間記録対象外のレコードがあったら、それより古いデータは平均の計算に加えない
if ($item->discard_elapsed_time) {
break;
}
$average += $item->span;
$divisor++;
}
if ($divisor > 0) {
$average /= $divisor;
}
$summary = DB::select(<<<'SQL'
SELECT
max(span) AS longest,
min(span) AS shortest,
sum(span) AS total_times
FROM
(
SELECT
extract(epoch from ejaculated_date - lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC)) AS span,
discard_elapsed_time
FROM
ejaculations
WHERE
user_id = :user_id
ORDER BY
ejaculated_date DESC
) AS temp
WHERE
discard_elapsed_time = FALSE
SQL
, ['user_id' => $user->id]);
$total = $user->ejaculations()->count();
$view->with(compact('latestEjaculation', 'currentSession', 'average', 'summary', 'total'));
}
}

24
app/Information.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Information extends Model
{
use SoftDeletes;
const CATEGORIES = [
0 => ['label' => 'お知らせ', 'class' => 'badge-info'],
1 => ['label' => 'アップデート', 'class' => 'badge-success'],
2 => ['label' => '不具合情報', 'class' => 'badge-danger'],
3 => ['label' => 'メンテナンス', 'class' => 'badge-warning']
];
protected $fillable = [
'category', 'pinned', 'title', 'content'
];
protected $dates = ['deleted_at'];
}

23
app/Like.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
class Like extends Model
{
use HasEagerLimit;
protected $fillable = ['user_id', 'ejaculation_id'];
public function user()
{
return $this->belongsTo(User::class);
}
public function ejaculation()
{
return $this->belongsTo(Ejaculation::class)->withLikes();
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Listeners;
use App\Events\LinkDiscovered;
use App\MetadataResolver\DeniedHostException;
use App\Services\MetadataResolveService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class LinkCollector
{
/** @var MetadataResolveService */
private $metadataResolveService;
/**
* Create the event listener.
*
* @param MetadataResolveService $metadataResolveService
*/
public function __construct(MetadataResolveService $metadataResolveService)
{
$this->metadataResolveService = $metadataResolveService;
}
/**
* Handle the event.
*
* @param LinkDiscovered $event
* @return void
*/
public function handle(LinkDiscovered $event)
{
try {
$this->metadataResolveService->execute($event->url);
} catch (DeniedHostException $e) {
// ignored
} catch (\Exception $e) {
// 今のところこのイベントは同期実行されるので、上流をクラッシュさせないために雑catchする
report($e);
}
}
}

80
app/Metadata.php Normal file
View File

@ -0,0 +1,80 @@
<?php
namespace App;
use Carbon\CarbonInterface;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Database\Eloquent\Model;
class Metadata extends Model
{
public $incrementing = false;
protected $primaryKey = 'url';
protected $keyType = 'string';
protected $fillable = ['url', 'title', 'description', 'image', 'expires_at'];
protected $visible = ['url', 'title', 'description', 'image', 'expires_at', 'tags'];
protected $dates = ['created_at', 'updated_at', 'expires_at', 'error_at'];
public function tags()
{
return $this->belongsToMany(Tag::class)->withTimestamps();
}
public function needRefresh(): bool
{
return $this->isExpired() || $this->error_at !== null;
}
public function isExpired(): bool
{
return $this->expires_at !== null && $this->expires_at < now();
}
public function storeException(CarbonInterface $error_at, \Exception $exception): self
{
$this->prepareFieldsOnError();
$this->error_at = $error_at;
$this->error_exception_class = get_class($exception);
$this->error_body = $exception->getMessage();
if ($exception instanceof RequestException) {
$this->error_http_code = $exception->getCode();
} else {
$this->error_http_code = null;
}
$this->error_count++;
return $this;
}
public function storeError(CarbonInterface $error_at, string $body, ?int $httpCode = null): self
{
$this->prepareFieldsOnError();
$this->error_at = $error_at;
$this->error_exception_class = null;
$this->error_body = $body;
$this->error_http_code = $httpCode;
$this->error_count++;
return $this;
}
public function clearError(): self
{
$this->error_at = null;
$this->error_exception_class = null;
$this->error_body = null;
$this->error_http_code = null;
$this->error_count = 0;
return $this;
}
private function prepareFieldsOnError()
{
$this->title = $this->title ?? '';
$this->description = $this->description ?? '';
$this->image = $this->image ?? '';
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Exception\TransferException;
use Illuminate\Support\Facades\Log;
use Psr\Http\Message\ResponseInterface;
class ActivityPubResolver implements Resolver, Parser
{
/**
* @var \GuzzleHttp\Client
*/
private $activityClient;
public function __construct()
{
$this->activityClient = new \GuzzleHttp\Client([
'headers' => [
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
]
]);
}
public function resolve(string $url): Metadata
{
$res = $this->activityClient->get($url);
if ($res->getStatusCode() === 200) {
return $this->parse($res->getBody());
} else {
throw new \RuntimeException("{$res->getStatusCode()}: $url");
}
}
public function parse(string $json): Metadata
{
$activityOrObject = json_decode($json, true);
$object = $activityOrObject['object'] ?? $activityOrObject;
if ($object['type'] !== 'Note') {
throw new UnsupportedContentException('Unsupported object type: ' . $object['type']);
}
$metadata = new Metadata();
$metadata->title = isset($object['attributedTo']) ? $this->getTitleFromActor($object['attributedTo']) : '';
$metadata->description .= isset($object['summary']) ? $object['summary'] . ' | ' : '';
$metadata->description .= isset($object['content']) ? $this->html2text($object['content']) : '';
$metadata->image = $object['attachment'][0]['url'] ?? '';
return $metadata;
}
private function getTitleFromActor(string $url): string
{
try {
$res = $this->activityClient->get($url);
if ($res->getStatusCode() !== 200) {
Log::info(self::class . ': Actorの取得に失敗 URL=' . $url);
return '';
}
$actor = json_decode($res->getBody(), true);
$title = $actor['name'] ?? '';
if (isset($actor['preferredUsername'])) {
$title .= ' (@' . $actor['preferredUsername'] . '@' . parse_url($actor['id'], PHP_URL_HOST) . ')';
}
return $title;
} catch (TransferException $e) {
Log::info(self::class . ': Actorの取得に失敗 URL=' . $url);
return '';
}
}
private function html2text(string $html): string
{
if (empty($html)) {
return '';
}
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
$html = preg_replace('~<br\s*/?\s*>|</p>\s*<p[^>]*>~i', "\n", $html);
$dom = new \DOMDocument();
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
return $dom->textContent;
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\MetadataResolver;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
class CienResolver extends MetadataResolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$html = (string) $res->getBody();
$metadata = $this->ogpResolver->parse($html);
$crawler = new Crawler($html);
// OGPのデフォルトはバナーなので、投稿に使える画像があればそれを使う
$selector = 'img[data-actual*="image-web"]';
if ($crawler->filter($selector)->count() !== 0) {
$metadata->image = $crawler->filter($selector)->attr('data-actual');
}
// JWTがついていれば画像URLのJWTから有効期限を拾う
parse_str(parse_url($metadata->image, PHP_URL_QUERY), $params);
if (isset($params['jwt'])) {
$parts = explode('.', $params['jwt']);
if (count($parts) !== 3) {
throw new \RuntimeException('Invalid jwt. Image=' . $metadata->image . ' Source=' . $url);
}
$payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $parts[1])), true);
$metadata->expires_at = Carbon::createFromTimestamp($payload['exp']);
}
return $metadata;
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class DLsiteResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
/**
* HTMLからタグとして利用可能な情報を抽出する
* @param string $html ページ HTML
* @return string[] タグ
*/
public function extractTags(string $html): array
{
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new \DOMXPath($dom);
$genreNode = $xpath->query("//div[@class='main_genre'][1]");
if ($genreNode->length === 0) {
return [];
}
$tagsNode = $genreNode->item(0)->getElementsByTagName('a');
$tags = [];
for ($i = 0; $i <= $tagsNode->length - 1; $i++) {
$tags[] = $tagsNode->item($i)->textContent;
}
// 重複削除
$tags = array_values(array_unique($tags));
sort($tags);
return $tags;
}
public function resolve(string $url): Metadata
{
//アフィリエイトの場合は普通のURLに変換
// ID型
if (preg_match('~/dlaf/=(/.+/.+)?/link/~', $url)) {
preg_match('~www\.dlsite\.com/(?P<genre>.+)/dlaf/=(/.+/.+)?/link/work/aid/(?P<AffiliateId>.+)/id/(?P<titleId>..\d+)(\.html)?~', $url, $matches);
$url = "https://www.dlsite.com/{$matches['genre']}/work/=/product_id/{$matches['titleId']}.html";
}
// URL型
if (strpos($url, '/dlaf/=/aid/') !== false) {
preg_match('~www\.dlsite\.com/.+/dlaf/=/aid/.+/url/(?P<url>.+)~', $url, $matches);
$affiliateUrl = urldecode($matches['url']);
if (preg_match('~www\.dlsite\.com/.+/(work|announce)/=/product_id/..\d+(\.html)?~', $affiliateUrl, $matches)) {
$url = $affiliateUrl;
} else {
throw new \RuntimeException("アフィリエイト先のリンクがDLsiteのタイトルではありません: $affiliateUrl");
}
}
//スマホページの場合はPCページに正規化
if (strpos($url, '-touch') !== false) {
$url = str_replace('-touch', '', $url);
}
$res = $this->client->get($url);
$metadata = $this->ogpResolver->parse($res->getBody());
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));
$xpath = new \DOMXPath($dom);
// OGPタイトルから[]に囲まれているmakerを取得する
// 複数の作者がいる場合スペース区切りになるためexplodeしている
// スペースを含むmakerの場合名前の一部しか取れないが動作には問題ない
preg_match('~ \[([^\[\]]*)\] (予告作品 )?\| DLsite(がるまに)?$~', $metadata->title, $match);
$makers = explode(' ', $match[1]);
//フォローボタン(.add_follow)はテキストを含んでしまうことがあるので要素を削除しておく
$followButtonNode = $xpath->query('//*[@class="add_follow"]')->item(0);
$followButtonNode->parentNode->removeChild($followButtonNode);
// maker, makerHeadを探す
// makers
// #work_makerから「makerを含むテキスト」を持つ要素を持つtdを探す
// 作者名単体の場合もあるし、"作者A / 作者B"のようになることもある
$makersNode = $xpath->query('//*[@id="work_maker"]//*[contains(text(), "' . $makers[0] . '")]/ancestor::td')->item(0);
// nbspをspaceに置換
$makers = trim(str_replace("\xc2\xa0", ' ', $makersNode->textContent));
// makersHaed
// $makerNode(td)に対するthを探す
// "著者", "サークル名", "ブランド名"など
$makersHeadNode = $xpath->query('preceding-sibling::th', $makersNode)->item(0);
$makersHead = trim($makersHeadNode->textContent);
// 余分な文を消す
// OGPタイトルから作者名とサイト名を消す
$metadata->title = trim(preg_replace('~ \[[^\[\]]*\] (予告作品 )?\| DLsite(がるまに)?$~', '', $metadata->title));
// OGP説明文から定型文を消す
if (strpos($url, 'dlsite.com/eng/') || strpos($url, 'dlsite.com/ecchi-eng/')) {
$metadata->description = preg_replace('~DLsite.+ is a download shop for .+With a huge selection of products, we\'re sure you\'ll find whatever tickles your fancy\. DLsite is one of the greatest indie contents download shops in Japan\.$~', '', $metadata->description);
} else {
$metadata->description = preg_replace('~「DLsite.+」は.+のダウンロードショップ。お気に入りの作品をすぐダウンロードできてすぐ楽しめる毎日更新しているのであなたが探している作品にきっと出会えます。国内最大級の二次元総合ダウンロードショップ「DLsite」$~', '', $metadata->description);
}
$metadata->description = trim(strip_tags($metadata->description));
// 整形
$metadata->description = $makersHead . ': ' . $makers . PHP_EOL . $metadata->description;
$metadata->image = str_replace('img_sam.jpg', 'img_main.jpg', $metadata->image);
$metadata->tags = $this->extractTags($res->getBody());
return $metadata;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\MetadataResolver;
use Exception;
use Throwable;
/**
* メタデータの解決を禁止しているホストに対して取得を試み、ブロックされたことを表します。
*/
class DeniedHostException extends Exception
{
private $url;
public function __construct(string $url, Throwable $previous = null)
{
parent::__construct("Access denied by system policy: $url", 0, $previous);
$this->url = $url;
}
public function getUrl(): string
{
return $this->url;
}
public function getHost(): string
{
return parse_url($this->url, PHP_URL_HOST);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class DeviantArtResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get('https://backend.deviantart.com/oembed?url=' . $url);
$data = json_decode($res->getBody()->getContents(), true);
$metadata = new Metadata();
$metadata->title = $data['title'] ?? '';
$metadata->description = 'By ' . $data['author_name'];
$metadata->image = $data['url'];
if (isset($data['tags'])) {
$metadata->tags = explode(', ', $data['tags']);
}
return $metadata;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\MetadataResolver;
use RuntimeException;
use Throwable;
/**
* ContentProviderの提供するrobots.txtによってクロールが拒否された場合にスローされます。
*/
class DisallowedByProviderException extends RuntimeException
{
private $url;
public function __construct(string $url, Throwable $previous = null)
{
parent::__construct("Access denied by robots.txt: $url", 0, $previous);
$this->url = $url;
}
public function getUrl(): string
{
return $this->url;
}
public function getHost(): string
{
return parse_url($this->url, PHP_URL_HOST);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class FantiaResolver implements Resolver
{
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata
{
preg_match("~posts/(\d+)~", $url, $match);
$postId = $match[1];
$res = $this->client->get("https://fantia.jp/api/v1/posts/{$postId}");
$data = json_decode(str_replace('\r\n', '\n', (string) $res->getBody()), true);
$post = $data['post'];
$tags = array_map(function ($tag) {
return $tag['name'];
}, $post['tags']);
$metadata = new Metadata();
$metadata->title = $post['title'] ?? '';
$metadata->description = 'サークル: ' . $post['fanclub']['fanclub_name_with_creator_name'] . PHP_EOL . $post['comment'];
$metadata->image = str_replace('micro', 'main', $post['thumb_micro']) ?? '';
$metadata->tags = array_merge($tags, [$post['fanclub']['creator_name']]);
return $metadata;
}
}

View File

@ -0,0 +1,108 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use Symfony\Component\DomCrawler\Crawler;
class FanzaResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
/**
* arrayの各要素をtrim・スペースの_置換をした後、重複した値を削除してキーを詰め直す
*
* @param array $array
*
* @return array 処理されたarray
*/
public function array_finish(array $array): array
{
$array = array_map('trim', $array);
$array = array_map((function ($value) {
return str_replace(' ', '_', $value);
}), $array);
$array = array_unique($array);
$array = array_values($array);
return $array;
}
public function resolve(string $url): Metadata
{
$cookieJar = CookieJar::fromArray(['age_check_done' => '1'], 'dmm.co.jp');
$res = $this->client->get($url, ['cookies' => $cookieJar]);
$html = (string) $res->getBody();
$crawler = new Crawler($html);
// 動画
if (preg_match('~www\.dmm\.co\.jp/digital/(videoa|videoc|anime)/-/detail~', $url)) {
$metadata = new Metadata();
$metadata->title = trim($crawler->filter('#title')->text(''));
$metadata->description = trim(strip_tags(str_replace('【FANZA(ファンザ)】', '', $crawler->filter('meta[name="description"]')->attr('content'))));
$metadata->image = preg_replace("~(pr|ps)\.jpg$~", 'pl.jpg', $crawler->filter('meta[property="og:image"]')->attr('content'));
$metadata->tags = $this->array_finish($crawler->filter('.box-rank+table a[href*="list/=/article="]')->extract(['_text']));
return $metadata;
}
// 同人
if (mb_strpos($url, 'www.dmm.co.jp/dc/doujin/-/detail/') !== false) {
$genre = $this->array_finish($crawler->filter('.m-productInformation a:not([href="#update-top"])')->extract(['_text']));
$genre = array_filter($genre, (function ($text) {
return !preg_match('~OFF対象$~', $text);
}));
$metadata = new Metadata();
$metadata->title = $crawler->filter('meta[property="og:title"]')->attr('content');
$metadata->description = trim($crawler->filter('.summary__txt')->text(''));
$metadata->image = $crawler->filter('meta[property="og:image"]')->attr('content');
$metadata->tags = array_merge($genre, [$crawler->filter('.circleName__txt')->text('')]);
return $metadata;
}
// 電子書籍
if (mb_strpos($url, 'book.dmm.co.jp/detail/') !== false) {
$metadata = new Metadata();
$metadata->title = trim($crawler->filter('#title')->text(''));
$metadata->description = trim($crawler->filter('.m-boxDetailProduct__info__story')->text(''));
$metadata->image = preg_replace("~(pr|ps)\.jpg$~", 'pl.jpg', $crawler->filter('meta[property="og:image"]')->attr('content'));
$metadata->tags = $this->array_finish($crawler->filter('.m-boxDetailProductInfoMainList__description__list__item, .m-boxDetailProductInfo__list__description__item a')->extract(['_text']));
return $metadata;
}
// PCゲーム
if (mb_strpos($url, 'dlsoft.dmm.co.jp/detail/') !== false) {
$metadata = new Metadata();
$metadata->title = trim($crawler->filter('#title')->text(''));
$metadata->description = trim($crawler->filter('.area-detail-read .text-overflow')->text(''));
$metadata->image = preg_replace("~(pr|ps)\.jpg$~", 'pl.jpg', $crawler->filter('meta[property="og:image"]')->attr('content'));
$metadata->tags = $this->array_finish($crawler->filter('.container02 table a[href*="list/article="]')->extract(['_text']));
return $metadata;
}
// 上で特に対応しなかったURL 画像の置換くらいはしておく
$metadata = $this->ogpResolver->parse($html);
$metadata->image = preg_replace("~(pr|ps)\.jpg$~", 'pl.jpg', $metadata->image);
return $metadata;
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use Symfony\Component\DomCrawler\Crawler;
class HentaiFoundryResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
private function nbsp2space(string $string): string
{
return str_replace("\xc2\xa0", ' ', $string);
}
private function br2nl(string $string): string
{
return str_replace('<br>', PHP_EOL, $string);
}
public function resolve(string $url): Metadata
{
$res = $this->client->get(
http_build_url($url, ['query' => 'enterAgree=1']),
['cookies' => new CookieJar()]
);
$metadata = new Metadata();
$crawler = new Crawler((string) $res->getBody());
$author = $crawler->filter('#picBox .boxtitle a')->text();
$description = trim(strip_tags($this->nbsp2space($this->br2nl($crawler->filter('.picDescript')->html()))));
$metadata->title = $crawler->filter('#picBox .boxtitle .imageTitle')->text();
$metadata->description = 'by ' . $author . PHP_EOL . $description;
$metadata->image = 'https:' . $crawler->filter('img[src^="//picture"]')->attr('src');
$metadata->tags = $crawler->filter('a[rel="tag"]')->extract('_text');
return $metadata;
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
class IwaraResolver implements Resolver
{
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$metadata = new Metadata();
$html = (string) $res->getBody();
$crawler = new Crawler($html);
$infoElements = $crawler->filter('#video-player + div, .field-name-field-video-url + div, .field-name-field-images + div');
$title = $infoElements->filter('h1.title')->text();
$author = $infoElements->filter('.username')->text();
$description = $infoElements->filter('.field-type-text-with-summary')->text('');
$tags = $infoElements->filter('a[href^="/videos"], a[href^="/images"]')->extract('_text');
// 役に立たないタグを削除する
$tags = array_values(array_diff($tags, ['Uncategorized', 'Other']));
array_push($tags, $author);
$metadata->title = $title;
$metadata->description = '投稿者: ' . $author . PHP_EOL . trim($description);
$metadata->tags = $tags;
// iwara video
if ($crawler->filter('#video-player')->count()) {
$metadata->image = 'https:' . $crawler->filter('#video-player')->attr('poster');
}
// youtube
if ($crawler->filter('iframe[src^="//www.youtube.com"]')->count()) {
if (preg_match('~youtube\.com/embed/(\S+)\?~', $crawler->filter('iframe[src^="//www.youtube.com"]')->attr('src'), $matches) === 1) {
$youtubeId = $matches[1];
$metadata->image = 'https://img.youtube.com/vi/' . $youtubeId . '/maxresdefault.jpg';
}
}
// images
if ($crawler->filter('.field-name-field-images')->count()) {
$metadata->image = 'https:' . $crawler->filter('.field-name-field-images a')->first()->attr('href');
}
return $metadata;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
class Kb10uyShortStoryServerResolver implements Resolver
{
protected const EXCLUDED_TAGS = ['R-15', 'R-18'];
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$html = (string) $res->getBody();
$crawler = new Crawler($html);
$infoElement = $crawler->filter('div.post-info');
$metadata = new Metadata();
$metadata->title = $infoElement->filter('h1')->text();
$metadata->description = trim($infoElement->filter('p.summary')->text());
$metadata->tags = array_values(array_diff($infoElement->filter('ul.tags > li.tag > a')->extract('_text'), self::EXCLUDED_TAGS));
return $metadata;
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class KomifloResolver implements Resolver
{
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata
{
if (preg_match('~komiflo\.com(?:/#!)?/comics/(\\d+)~', $url, $matches) !== 1) {
throw new \RuntimeException("Unmatched URL Pattern: $url");
}
$id = $matches[1];
$res = $this->client->get('https://api.komiflo.com/content/id/' . $id);
$json = json_decode($res->getBody()->getContents(), true);
$metadata = new Metadata();
$metadata->title = $json['content']['data']['title'] ?? '';
$metadata->description = ($json['content']['attributes']['artists']['children'][0]['data']['name'] ?? '?') .
' - ' . ($json['content']['parents'][0]['data']['title'] ?? '?');
$metadata->image = 'https://t.komiflo.com/564_mobile_large_3x/' . $json['content']['named_imgs']['cover']['filename'];
// 作者情報
if (!empty($json['content']['attributes']['artists']['children'])) {
foreach ($json['content']['attributes']['artists']['children'] as $artist) {
$metadata->tags[] = preg_replace('/\s/', '_', $artist['data']['name']);
}
}
// タグ
if (!empty($json['content']['attributes']['tags']['children'])) {
$tags = [];
foreach ($json['content']['attributes']['tags']['children'] as $tag) {
$tags[] = preg_replace('/\s/', '_', $tag['data']['name']);
}
sort($tags);
$metadata->tags = array_merge($metadata->tags, $tags);
}
return $metadata;
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
class MelonbooksResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$cookieJar = CookieJar::fromArray(['AUTH_ADULT' => '1'], 'www.melonbooks.co.jp');
$res = $this->client->get($url, ['cookies' => $cookieJar]);
$metadata = $this->ogpResolver->parse($res->getBody());
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));
$xpath = new \DOMXPath($dom);
$descriptionNodelist = $xpath->query('//div[@id="description"]//p');
$specialDescriptionNodelist = $xpath->query('//div[@id="special_description"]//p');
// censoredフラグの除去
if (mb_strpos($metadata->image, '&c=1') !== false) {
$metadata->image = preg_replace('/&c=1/u', '', $metadata->image);
}
// 抽出
preg_match('~^(.+)(.+))の通販・購入はメロンブックス$~', $metadata->title, $match);
$title = $match[1];
$maker = $match[2];
// 整形
$description = 'サークル: ' . $maker . "\n";
if ($specialDescriptionNodelist->length !== 0) {
$description .= trim(str_replace('<br>', "\n", $specialDescriptionNodelist->item(0)->nodeValue)) . "\n";
if ($specialDescriptionNodelist->length === 2) {
$description .= "\n";
$description .= trim(str_replace('<br>', "\n", $specialDescriptionNodelist->item(1)->nodeValue)) . "\n";
}
}
if ($descriptionNodelist->length !== 0) {
$description .= trim(str_replace('<br>', "\n", $descriptionNodelist->item(0)->nodeValue));
}
$metadata->title = $title;
$metadata->description = trim($description);
return $metadata;
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\MetadataResolver;
use Carbon\Carbon;
class Metadata
{
/** @var string タイトル */
public $title = '';
/** @var string 概要 */
public $description = '';
/** @var string サムネイルのURL */
public $image = '';
/** @var Carbon|null メタデータの有効期限 */
public $expires_at = null;
/**
* @var string[] タグ
* チェックインタグと同様に保存されるため、スペースや改行文字を含めてはいけません。
*/
public $tags = [];
/**
* 重複を排除し、正規化を行ったタグの集合を返します。
* @return string[]
*/
public function normalizedTags(): array
{
$tags = [];
foreach ($this->tags as $tag) {
$tag = $this->sanitize($tag);
$tag = $this->trim($tag);
$tags[$tag] = true;
}
return array_keys($tags);
}
private function sanitize(string $value): string
{
return preg_replace('/\r?\n/u', ' ', $value);
}
private function trim(string $value): string
{
return trim($value);
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
class MetadataResolver implements Resolver
{
public $rules = [
'~(((sp\.)?seiga\.nicovideo\.jp/seiga(/#!)?|nico\.ms))/im~' => NicoSeigaResolver::class,
'~nijie\.info/view(_popup)?\.php~' => NijieResolver::class,
'~komiflo\.com(/#!)?/comics/(\\d+)~' => KomifloResolver::class,
'~www\.melonbooks\.co\.jp/detail/detail\.php~' => MelonbooksResolver::class,
'~ec\.toranoana\.(jp|shop)/(tora|joshi)(_[rd]+)?/(ec|digi)/item/~' => ToranoanaResolver::class,
'~iwara\.tv/(videos|images)/.*~' => IwaraResolver::class,
'~www\.dlsite\.com/.*/(work|announce)/=/product_id/..\d+(\.html)?~' => DLsiteResolver::class,
'~www\.dlsite\.com/.*/dlaf/=(/.+/.+)?/link/work/aid/.+(/id)?/..\d+(\.html)?~' => DLsiteResolver::class,
'~www\.dlsite\.com/.*/dlaf/=/aid/.+/url/.+~' => DLsiteResolver::class,
'~dlsite\.jp/...tw/..\d+~' => DLsiteResolver::class,
'~www\.pixiv\.net/member_illust\.php\?illust_id=\d+~' => PixivResolver::class,
'~www\.pixiv\.net/(en/)?artworks/\d+~' => PixivResolver::class,
'~www\.pixiv\.net/user/\d+/series/\d+~' => PixivResolver::class,
'~fantia\.jp/posts/\d+~' => FantiaResolver::class,
'~dmm\.co\.jp/~' => FanzaResolver::class,
'~www\.patreon\.com/~' => PatreonResolver::class,
'~www\.deviantart\.com/.*/art/.*~' => DeviantArtResolver::class,
'~\.syosetu\.com/n\d+[a-z]+~' => NarouResolver::class,
'~ci-en\.(jp|net|dlsite\.com)/creator/\d+/article/\d+~' => CienResolver::class,
'~www\.plurk\.com\/p\/.*~' => PlurkResolver::class,
'~store\.steampowered\.com/app/\d+~' => SteamResolver::class,
'~www\.xtube\.com/video-watch/.*-\d+$~'=> XtubeResolver::class,
'~ss\.kb10uy\.org/posts/\d+$~' => Kb10uyShortStoryServerResolver::class,
'~www\.hentai-foundry\.com/pictures/user/.+/\d+/.+~'=> HentaiFoundryResolver::class,
'~(www\.)?((mobile|m)\.)?twitter\.com/(#!/)?[0-9a-zA-Z_]{1,15}/status(es)?/([0-9]+)/?(\\?.+)?$~' => TwitterResolver::class,
];
public $mimeTypes = [
'application/activity+json' => ActivityPubResolver::class,
'application/ld+json' => ActivityPubResolver::class,
'text/html' => OGPResolver::class,
'*/*' => OGPResolver::class
];
public $defaultResolver = OGPResolver::class;
public function resolve(string $url): Metadata
{
foreach ($this->rules as $pattern => $class) {
if (preg_match($pattern, $url) === 1) {
try {
/** @var Resolver $resolver */
$resolver = app($class);
return $resolver->resolve($url);
} catch (UnsupportedContentException $e) {
}
}
}
try {
return $this->resolveWithAcceptHeader($url);
} catch (UnsupportedContentException $e) {
}
if (isset($this->defaultResolver)) {
/** @var Resolver $resolver */
$resolver = app($this->defaultResolver);
return $resolver->resolve($url);
}
throw new \UnexpectedValueException('URL not matched.');
}
public function resolveWithAcceptHeader(string $url): Metadata
{
try {
// Rails等はAcceptに */* が入っていると、ブラウザの適当なAcceptヘッダだと判断して全部無視してしまう。
// c.f. https://github.com/rails/rails/issues/9940
// そこでここでは */* を「Acceptヘッダを無視してきたレスポンスよくある」のハンドラとして扱い、
// Acceptヘッダには */* を足さないことにする。
$acceptTypes = array_diff(array_keys($this->mimeTypes), ['*/*']);
$client = app(Client::class);
$res = $client->request('GET', $url, [
'headers' => [
'Accept' => implode(', ', $acceptTypes)
]
]);
if ($res->getStatusCode() === 200) {
preg_match('/^[^;\s]+/', $res->getHeaderLine('Content-Type'), $matches);
$mimeType = $matches[0];
if (isset($this->mimeTypes[$mimeType])) {
$class = $this->mimeTypes[$mimeType];
$parser = app($class);
return $parser->parse($res->getBody());
}
if (isset($this->mimeTypes['*/*'])) {
$class = $this->mimeTypes['*/*'];
$parser = app($class);
return $parser->parse($res->getBody());
}
} else {
// code < 400 && code !== 200 => fallback
}
} catch (ClientException $e) {
// 406 Not Acceptable は多分Acceptが原因なので無視してフォールバック
if ($e->getResponse()->getStatusCode() !== 406) {
throw $e;
}
} catch (ServerException $e) {
// 5xx は変なAcceptが原因かもしれないので無視してフォールバック
}
throw new UnsupportedContentException();
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
class NarouResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$cookieJar = CookieJar::fromArray(['over18' => 'yes'], '.syosetu.com');
$res = $this->client->get($url, ['cookies' => $cookieJar]);
$metadata = $this->ogpResolver->parse($res->getBody());
$metadata->description = '';
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'ASCII,JIS,UTF-8,eucJP-win,SJIS-win'));
$xpath = new \DOMXPath($dom);
$description = [];
// 作者名
$writerNodes = $xpath->query('//*[contains(@class, "novel_writername")]');
if ($writerNodes->length !== 0 && !empty($writerNodes->item(0)->textContent)) {
$description[] = trim($writerNodes->item(0)->textContent);
}
// あらすじ
$exNodes = $xpath->query('//*[@id="novel_ex"]');
if ($exNodes->length !== 0 && !empty($exNodes->item(0)->textContent)) {
$summary = trim($exNodes->item(0)->textContent);
$description[] = mb_strimwidth($summary, 0, 101, '…'); // 100 + '…'(1)
}
$metadata->description = implode(' / ', $description);
return $metadata;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
class NicoSeigaResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$html = (string)$res->getBody();
$metadata = $this->ogpResolver->parse($html);
$crawler = new Crawler($html);
// タグ
$excludeTags = ['R-15'];
$metadata->tags = array_values(array_diff($crawler->filter('.tag')->extract(['_text']), $excludeTags));
// ページURLからサムネイルURLに変換
preg_match('~https?://(?:(?:sp\\.)?seiga\\.nicovideo\\.jp/seiga(?:/#!)?|nico\\.ms)/im(\\d+)~', $url, $matches);
$metadata->image = "https://lohas.nicoseiga.jp/thumb/${matches[1]}l?";
return $metadata;
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use Illuminate\Support\Str;
use Symfony\Component\DomCrawler\Crawler;
class NijieResolver implements Resolver
{
/**
* @var Client
*/
protected $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
if (mb_strpos($url, '//sp.nijie.info') !== false) {
$url = preg_replace('~//sp\.nijie\.info~', '//nijie.info', $url);
}
if (mb_strpos($url, 'view_popup.php') !== false) {
$url = preg_replace('~view_popup\.php~', 'view.php', $url);
}
$res = $this->client->get($url);
$html = (string) $res->getBody();
$metadata = $this->ogpResolver->parse($html);
$crawler = new Crawler($html);
$json = $crawler->filter('script[type="application/ld+json"]')->first()->text();
// 改行がそのまま入っていることがあるのでデコード前にエスケープが必要
$data = json_decode(preg_replace('/\r?\n/', '\n', $json), true);
// DomCrawler内でjson内の日本語がHTMLエンティティに変換されるので、全要素に対してhtml_entity_decode
array_walk_recursive($data, function (&$v) {
$v = html_entity_decode($v);
});
$metadata->title = $data['name'];
$metadata->description = '投稿者: ' . $data['author']['name'] . PHP_EOL . $data['description'];
if (
isset($data['thumbnailUrl']) &&
!Str::endsWith($data['thumbnailUrl'], '.gif') &&
!Str::endsWith($data['thumbnailUrl'], '.mp4')
) {
// サムネイルからメイン画像に
$metadata->image = str_replace('__rs_l160x160/', '', $data['thumbnailUrl']);
}
$metadata->tags = $crawler->filter('#view-tag span.tag_name')->extract('_text');
return $metadata;
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\RequestOptions;
class OGPResolver implements Resolver, Parser
{
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata
{
return $this->parse($this->client->get($url, [RequestOptions::COOKIES => new CookieJar()])->getBody());
}
public function parse(string $html): Metadata
{
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'ASCII,JIS,UTF-8,eucJP-win,SJIS-win'));
$xpath = new \DOMXPath($dom);
$metadata = new Metadata();
$metadata->title = $this->findContent($xpath, '//meta[@*="og:title"]', '//meta[@*="twitter:title"]');
if (empty($metadata->title)) {
$nodes = $xpath->query('//title');
if ($nodes->length !== 0) {
$metadata->title = $nodes->item(0)->textContent;
}
}
$metadata->description = $this->findContent($xpath, '//meta[@*="og:description"]', '//meta[@*="twitter:description"]', '//meta[@name="description"]');
$metadata->image = $this->findContent($xpath, '//meta[@*="og:image"]', '//meta[@*="twitter:image"]');
return $metadata;
}
private function findContent(\DOMXPath $xpath, string ...$expressions)
{
foreach ($expressions as $expression) {
$nodes = $xpath->query($expression);
foreach ($nodes as $node) {
$content = $node->getAttribute('content');
if (!empty($content)) {
return $content;
}
}
}
return '';
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\MetadataResolver;
interface Parser
{
public function parse(string $body): Metadata;
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\MetadataResolver;
use Carbon\Carbon;
use GuzzleHttp\Client;
class PatreonResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$metadata = $this->ogpResolver->parse($res->getBody());
parse_str(parse_url($metadata->image, PHP_URL_QUERY), $query);
if (isset($query['token-time'])) {
$expires_at_unixtime = $query['token-time'];
$metadata->expires_at = Carbon::createFromTimestamp($expires_at_unixtime);
}
return $metadata;
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class PixivResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
/**
* 直リン可能な pixiv.cat のプロキシ URL に変換する
* HUGE THANKS TO PIXIV.CAT!
*
* @param string $pixivUrl i.pximg URL
*
* @return string i.pixiv.cat URL
*/
public function proxize(string $pixivUrl): string
{
return str_replace('i.pximg.net', 'i.pixiv.cat', $pixivUrl);
}
public function resolve(string $url): Metadata
{
if (preg_match('~www\.pixiv\.net/user/\d+/series/\d+~', $url, $matches)) {
$res = $this->client->get($url);
$metadata = $this->ogpResolver->parse($res->getBody());
$metadata->image = $this->proxize($metadata->image);
return $metadata;
}
$page = 0;
if (preg_match('~www\.pixiv\.net/(en/)?artworks/(?P<illustId>\d+)~', $url, $matches)) {
$illustId = $matches['illustId'];
} else {
parse_str(parse_url($url, PHP_URL_QUERY), $params);
$illustId = $params['illust_id'];
// 漫画ページページ数はmanga_bigならあるかも
if ($params['mode'] === 'manga_big' || $params['mode'] === 'manga') {
$page = $params['page'] ?? 0;
}
}
$res = $this->client->get('https://www.pixiv.net/ajax/illust/' . $illustId);
$json = json_decode($res->getBody()->getContents(), true);
$metadata = new Metadata();
$metadata->title = $json['body']['illustTitle'] ?? '';
$metadata->description = '投稿者: ' . $json['body']['userName'] . PHP_EOL . strip_tags(str_replace('<br />', PHP_EOL, $json['body']['illustComment'] ?? ''));
$metadata->image = $this->proxize($json['body']['urls']['regular'] ?? '');
// ページ数の指定がある場合は画像URLをそのページにする
if ($page != 0) {
$metadata->image = str_replace('_p0', '_p' . $page, $metadata->image);
}
// タグ
if (!empty($json['body']['tags']['tags'])) {
foreach ($json['body']['tags']['tags'] as $tag) {
// 一部の固定キーワードは無視
if (array_search($tag['tag'], ['R-18', 'イラスト', 'pixiv', 'ピクシブ'], true) === false) {
$metadata->tags[] = preg_replace('/\s/', '_', $tag['tag']);
}
}
}
return $metadata;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class PlurkResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$metadata = $this->ogpResolver->parse($res->getBody());
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));
$xpath = new \DOMXPath($dom);
$imageNode = $xpath->query('//div[@class="text_holder"]/a[1]')->item(0);
if ($imageNode) {
$metadata->image = $imageNode->getAttribute('href');
}
return $metadata;
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\MetadataResolver;
interface Resolver
{
public function resolve(string $url): Metadata;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\MetadataResolver;
use Throwable;
/**
* 規定回数以上の解決失敗により、メタデータの取得が不能となっている場合にスローされます。
*/
class ResolverCircuitBreakException extends \RuntimeException
{
public function __construct(int $errorCount, string $url, Throwable $previous = null)
{
parent::__construct("{$errorCount}回失敗しているためメタデータの取得を中断しました: {$url}", 0, $previous);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class SteamResolver implements Resolver
{
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata
{
if (preg_match('~store\.steampowered\.com/app/(\d+)~', $url, $matches) !== 1) {
throw new \RuntimeException("Unmatched URL Pattern: $url");
}
$appid = $matches[1];
$res = $this->client->get('https://store.steampowered.com/api/appdetails/?l=japanese&appids=' . $appid);
$json = json_decode($res->getBody()->getContents(), true);
if ($json[$appid]['success'] === false) {
throw new \RuntimeException("API response [$appid][success] is false: $url");
}
$data = $json[$appid]['data'];
$metadata = new Metadata();
$metadata->title = $data['name'] ?? '';
$metadata->description = strip_tags(str_replace('<br />', PHP_EOL, html_entity_decode($data['short_description'] ?? '')));
$metadata->image = $data['header_image'] ?? '';
return $metadata;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
class ToranoanaResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$res = $this->client->get($url);
$metadata = $this->ogpResolver->parse($res->getBody());
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));
$xpath = new \DOMXPath($dom);
$imgNode = $xpath->query('//*[@id="preview"]//img')->item(0);
if ($imgNode !== null) {
$metadata->image = $imgNode->getAttribute('src');
}
return $metadata;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class TwitterResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
$url = preg_replace('/(www\.)?(mobile|m)\.twitter\.com/u', 'twitter.com', $url);
$res = $this->client->get($url);
$html = (string) $res->getBody();
return $this->ogpResolver->parse($html);
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\MetadataResolver;
/**
* MetadataResolver内で未キャッチの例外が発生した場合にスローされます。
*/
class UncaughtResolverException extends \RuntimeException
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\MetadataResolver;
use Exception;
/**
* このResolverやParserが対応していないサイトであったことを表わします。
*/
class UnsupportedContentException extends Exception
{
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
class XtubeResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata
{
if (preg_match('~www\.xtube\.com/video-watch/.*-(\d+)$~', $url) !== 1) {
throw new \RuntimeException("Unmatched URL Pattern: $url");
}
$res = $this->client->get($url);
$html = (string) $res->getBody();
$metadata = $this->ogpResolver->parse($html);
$crawler = new Crawler($html);
$metadata->title = trim($crawler->filter('.underPlayerRateForm h1')->text(''));
// $metadata->description = trim($crawler->filter('.fullDescription ')->text(''));
$metadata->image = str_replace('m=eSuQ8f', 'm=eaAaaEFb', $metadata->image);
$metadata->image = str_replace('240X180', 'original', $metadata->image);
$metadata->tags = array_map('trim', $crawler->filter('.tagsCategories a')->extract('_text'));
return $metadata;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Policies;
use App\Ejaculation;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class EjaculationPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* @return void
*/
public function __construct()
{
//
}
public function edit(User $user, Ejaculation $ejaculation): bool
{
return $user->id === $ejaculation->user_id;
}
}

View File

@ -2,7 +2,12 @@
namespace App\Providers;
use App\MetadataResolver\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Parsedown;
class AppServiceProvider extends ServiceProvider
{
@ -13,7 +18,11 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
//
Blade::directive('parsedown', function ($expression) {
return "<?php echo app('parsedown')->text($expression); ?>";
});
stream_filter_register('convert.mbstring.*', 'Stream_Filter_Mbstring');
}
/**
@ -23,6 +32,18 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
//
$this->app->singleton(MetadataResolver::class, function ($app) {
return new MetadataResolver();
});
$this->app->singleton('parsedown', function () {
return Parsedown::instance();
});
$this->app->bind(Client::class, function () {
return new Client([
RequestOptions::HEADERS => [
'User-Agent' => 'TissueBot/1.0'
]
]);
});
}
}

View File

@ -2,8 +2,10 @@
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use App\Ejaculation;
use App\Policies\EjaculationPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
@ -14,6 +16,7 @@ class AuthServiceProvider extends ServiceProvider
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
Ejaculation::class => EjaculationPolicy::class,
];
/**
@ -25,6 +28,8 @@ class AuthServiceProvider extends ServiceProvider
{
$this->registerPolicies();
//
Gate::define('admin', function ($user) {
return $user->is_admin;
});
}
}

View File

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{

View File

@ -2,8 +2,10 @@
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
@ -13,9 +15,12 @@ class EventServiceProvider extends ServiceProvider
* @var array
*/
protected $listen = [
'App\Events\Event' => [
'App\Listeners\EventListener',
Registered::class => [
SendEmailVerificationNotification::class,
],
'App\Events\LinkDiscovered' => [
'App\Listeners\LinkCollector'
]
];
/**

View File

@ -0,0 +1,31 @@
<?php
namespace App\Providers;
use App\Utilities\Formatter;
use Illuminate\Support\ServiceProvider;
class FormatterServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Formatter::class, function ($app) {
return new Formatter();
});
}
}

View File

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{

View File

@ -0,0 +1,30 @@
<?php
namespace App\Providers;
use App\Http\ViewComposers\ProfileStatsComposer;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
View::composer('components.profile-stats', ProfileStatsComposer::class);
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
//
}
}

82
app/Rules/CsvDateTime.php Normal file
View File

@ -0,0 +1,82 @@
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
/**
* CSVインポート機能の日時バリデーションルール
* @package App\Rules
*/
class CsvDateTime implements Rule
{
const VALID_FORMATS = [
'Y/m/d H:i:s',
'Y/n/j G:i:s',
'Y/m/d H:i',
'Y/n/j G:i',
];
const MINIMUM_TIMESTAMP = 946652400; // 2000-01-01 00:00:00 JST
const MAXIMUM_TIMESTAMP = 4102412399; // 2099-12-31 23:59:59 JST
/** @var string Validation error message */
private $message = ':attributeの形式は "年/月/日 時:分" にしてください。';
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
// この辺の実装の元ネタは、LaravelのValidatesAttributes#validateDateFormat()
if (!is_string($value)) {
return false;
}
foreach (self::VALID_FORMATS as $format) {
$date = \DateTime::createFromFormat('!' . $format, $value);
if (!$date) {
continue;
}
$timestamp = (int) $date->format('U');
if ($timestamp < self::MINIMUM_TIMESTAMP || self::MAXIMUM_TIMESTAMP < $timestamp) {
$this->message = ':attributeは 2000/01/01 00:00 〜 2099/12/31 23:59 の間のみ対応しています。';
return false;
}
$formatted = $date->format($format);
if ($formatted === $value) {
return true;
}
}
return false;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return $this->message;
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class FuzzyBoolean implements Rule
{
public static function isTruthy($value): bool
{
if ($value === 1 || $value === '1') {
return true;
}
$lower = strtolower((string)$value);
return $lower === 'true';
}
public static function isFalsy($value): bool
{
if ($value === null || $value === '' || $value === 0 || $value === '0') {
return true;
}
$lower = strtolower((string)$value);
return $lower === 'false';
}
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return self::isTruthy($value) || self::isFalsy($value);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return __('validation.boolean');
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\Services;
use App\User;
use Illuminate\Support\Facades\DB;
use League\Csv\Writer;
class CheckinCsvExporter
{
/** @var User Target user */
private $user;
/** @var string Output filename */
private $filename;
/** @var string Output charset */
private $charset;
public function __construct(User $user, string $filename, string $charset)
{
$this->user = $user;
$this->filename = $filename;
$this->charset = $charset;
}
public function execute()
{
$csv = Writer::createFromPath($this->filename, 'wb');
$csv->setNewline("\r\n");
if ($this->charset === 'SJIS-win') {
$csv->addStreamFilter('convert.mbstring.encoding.UTF-8:SJIS-win');
}
$header = ['日時', 'ノート', 'オカズリンク', '非公開', 'センシティブ'];
for ($i = 1; $i <= 32; $i++) {
$header[] = "タグ{$i}";
}
$csv->insertOne($header);
DB::transaction(function () use ($csv) {
// TODO: そんなに読み取り整合性を保つ努力はしていないのと、chunkの件数これでいいか分からない
$this->user->ejaculations()->with('tags')->orderBy('ejaculated_date')
->chunk(1000, function ($ejaculations) use ($csv) {
foreach ($ejaculations as $ejaculation) {
$record = [
$ejaculation->ejaculated_date->format('Y/m/d H:i'),
$ejaculation->note,
$ejaculation->link,
self::formatBoolean($ejaculation->is_private),
self::formatBoolean($ejaculation->is_too_sensitive),
];
foreach ($ejaculation->tags->take(32) as $tag) {
$record[] = $tag->name;
}
$csv->insertOne($record);
}
});
});
}
private static function formatBoolean($value): string
{
return $value ? 'true' : 'false';
}
}

Some files were not shown because too many files have changed in this diff Show More