716 Commits

Author SHA1 Message Date
eai04191
5e9fa05be5 spoilerを画像にだけ適用するように変更 2020-01-28 01:47:40 +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エンティティのデコードを行ってしまうと " なども解除されてしまい、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
281 changed files with 93286 additions and 24249 deletions

166
.circleci/config.yml Normal file
View File

@@ -0,0 +1,166 @@
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 docker-php-ext-install zip
- run: sudo docker-php-ext-install pdo_pgsql
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 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]
indent_size = 2
[*.json]
indent_size = 2
[composer.json]
indent_size = 4

View File

@@ -1,16 +1,19 @@
APP_NAME=Laravel APP_NAME=Tissue
APP_ENV=local APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=true
APP_LOG_LEVEL=debug APP_LOG_LEVEL=debug
APP_URL=http://localhost APP_URL=http://localhost
DB_CONNECTION=mysql # テストにモックを使用するか falseの場合は実際のHTML等を取得してテストする
DB_HOST=127.0.0.1 TEST_USE_HTTP_MOCK=true
DB_PORT=3306
DB_DATABASE=homestead DB_CONNECTION=pgsql
DB_USERNAME=homestead DB_HOST=db
DB_PASSWORD=secret DB_PORT=5432
DB_DATABASE=tissue
DB_USERNAME=tissue
DB_PASSWORD=tissue
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
CACHE_DRIVER=file CACHE_DRIVER=file
@@ -22,12 +25,21 @@ REDIS_PASSWORD=null
REDIS_PORT=6379 REDIS_PORT=6379
MAIL_DRIVER=smtp MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io MAIL_HOST=smtp.sparkpostmail.com
MAIL_PORT=2525 MAIL_PORT=587
MAIL_USERNAME=null MAIL_USERNAME=SMTP_Injection
MAIL_PASSWORD=null MAIL_PASSWORD=null
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=support@mail.shikorism.net
MAIL_FROM_NAME=Tissue
SPARKPOST_SECRET=
PUSHER_APP_ID= PUSHER_APP_ID=
PUSHER_APP_KEY= PUSHER_APP_KEY=
PUSHER_APP_SECRET= PUSHER_APP_SECRET=
# (Optional) reCAPTCHA Key
# https://www.google.com/recaptcha
NOCAPTCHA_SECRET=
NOCAPTCHA_SITEKEY=

1
.gitattributes vendored
View File

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

11
.gitignore vendored
View File

@@ -1,13 +1,22 @@
/node_modules /node_modules
/public/css
/public/fonts
/public/js
/public/hot /public/hot
/public/storage /public/storage
/public/mix-manifest.json
/storage/*.key /storage/*.key
/vendor /vendor
/.idea /.idea
/.vscode
/.vagrant /.vagrant
Homestead.json Homestead.json
Homestead.yaml Homestead.yaml
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
.env .env
*.iml *.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__)
);

1
.stylelintignore Normal file
View File

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

34
Dockerfile Normal file
View File

@@ -0,0 +1,34 @@
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 \
&& docker-php-ext-install pdo_pgsql \
&& pecl install xdebug \
&& curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer \
&& composer global require hirak/prestissimo \
&& 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

100
README.md
View File

@@ -1,19 +1,101 @@
Tissue # Tissue
====
a.k.a. shikorism.net a.k.a. shikorism.net
シコリズムネットにて提供している夜のライフログサービスです。 シコリズムネットにて提供している夜のライフログサービスです。
(思想的には [shibafu528/SperMaster](https://github.com/shibafu528/SperMaster) の後継となります) (思想的には [shibafu528/SperMaster](https://github.com/shibafu528/SperMaster) の後継となります)
## 構成 ## 構成
* Laravel 5.4
* Materialize 0.99.0 (Materialでデザインする気が失せたので変更予定) - Laravel 5.5
- Bootstrap 4.3.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 等を平気で使います。

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

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,96 @@
namespace App; namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
class Ejaculation extends Model class Ejaculation extends Model
{ {
// use HasEagerLimit;
protected $fillable = [ protected $fillable = [
'user_id', 'ejaculated_date', 'user_id', 'ejaculated_date',
'note', 'geo_latitude', 'geo_longitude', 'note', 'geo_latitude', 'geo_longitude', 'link',
'is_private' 'is_private', 'is_too_sensitive'
]; ];
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 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_too_sensitive' => $this->is_too_sensitive,
]);
}
} }

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;
}
}

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,75 @@
<?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($id)
{
$information = Information::findOrFail($id);
return view('admin.info.edit')->with([
'info' => $information,
'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,63 @@
<?php
namespace App\Http\Controllers\Api;
use App\Metadata;
use App\MetadataResolver\MetadataResolver;
use App\Tag;
use App\Utilities\Formatter;
use Illuminate\Http\Request;
class CardController
{
/**
* @var MetadataResolver
*/
private $resolver;
/**
* @var Formatter
*/
private $formatter;
public function __construct(MetadataResolver $resolver, Formatter $formatter)
{
$this->resolver = $resolver;
$this->formatter = $formatter;
}
public function show(Request $request)
{
$request->validate([
'url:required|url'
]);
$url = $this->formatter->normalizeUrl($request->input('url'));
$metadata = Metadata::find($url);
if ($metadata === null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
$resolved = $this->resolver->resolve($url);
$metadata = Metadata::updateOrCreate(['url' => $url], [
'title' => $resolved->title,
'description' => $resolved->description,
'image' => $resolved->image,
'expires_at' => $resolved->expires_at
]);
$tagIds = [];
foreach ($resolved->tags as $tagName) {
$tag = Tag::firstOrCreate(['name' => $tagName]);
$tagIds[] = $tag->id;
}
$metadata->tags()->sync($tagIds);
}
$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

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

View File

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

View File

@@ -2,59 +2,186 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Validator;
use App\Ejaculation; use App\Ejaculation;
use App\Events\LinkDiscovered;
use App\Tag;
use App\User;
use Carbon\Carbon;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Validator;
class EjaculationController extends Controller class EjaculationController extends Controller
{ {
public function create() public function create(Request $request)
{ {
return view('ejaculation.checkin'); $defaults = [
'date' => $request->input('date', date('Y/m/d')),
'time' => $request->input('time', date('H:i')),
'link' => $request->input('link', ''),
'tags' => $request->input('tags', ''),
'note' => $request->input('note', ''),
'is_private' => $request->input('is_private', 0) == 1,
'is_too_sensitive' => $request->input('is_too_sensitive', 0) == 1
];
return view('ejaculation.checkin')->with('defaults', $defaults);
} }
public function store(Request $request) public function store(Request $request)
{ {
Validator::make($request->all(), [ $inputs = $request->all();
$validator = Validator::make($inputs, [
'date' => 'required|date_format:Y/m/d', 'date' => 'required|date_format:Y/m/d',
'time' => 'required|date_format:H:i', 'time' => 'required|date_format:H:i',
'note' => 'nullable|string|max:500', 'note' => 'nullable|string|max:500',
])->after(function ($validator) use ($request) { 'link' => 'nullable|url|max:2000',
'tags' => 'nullable|string',
])->after(function ($validator) use ($request, $inputs) {
// 日時の重複チェック // 日時の重複チェック
$dt = $request->input('date') . ' ' . $request->input('time'); if (!$validator->errors()->hasAny(['date', 'time'])) {
if (Ejaculation::where(['user_id' => Auth::id(), 'ejaculated_date' => $dt])->count()) { $dt = $inputs['date'] . ' ' . $inputs['time'];
$validator->errors()->add('datetime', '既にこの日時にチェックインしているため、登録できません。'); if (Ejaculation::where(['user_id' => Auth::id(), 'ejaculated_date' => $dt])->count()) {
$validator->errors()->add('datetime', '既にこの日時にチェックインしているため、登録できません。');
}
} }
})->validate(); });
Ejaculation::create([ if ($validator->fails()) {
return redirect()->route('checkin')->withErrors($validator)->withInput();
}
$ejaculation = Ejaculation::create([
'user_id' => Auth::id(), 'user_id' => Auth::id(),
'ejaculated_date' => $request->input('date') . ' ' . $request->input('time'), 'ejaculated_date' => Carbon::createFromFormat('Y/m/d H:i', $inputs['date'] . ' ' . $inputs['time']),
'note' => $request->input('note') ?? '', 'note' => $inputs['note'] ?? '',
'is_private' => $request->has('is_private') ?? false 'link' => $inputs['link'] ?? '',
'is_private' => $request->has('is_private') ?? false,
'is_too_sensitive' => $request->has('is_too_sensitive') ?? false
]); ]);
return redirect()->route('home')->with('status', 'チェックインしました!'); $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 show($id)
{ {
// TODO: not implemented $ejaculation = Ejaculation::where('id', $id)
->withLikes()
->firstOrFail();
$user = User::findOrFail($ejaculation->user_id);
// 1つ前のチェックインからの経過時間を求める
$previousEjaculation = Ejaculation::select('ejaculated_date')
->where('user_id', $ejaculation->user_id)
->where('ejaculated_date', '<', $ejaculation->ejaculated_date)
->orderByDesc('ejaculated_date')
->first();
if (!empty($previousEjaculation)) {
$ejaculatedSpan = $ejaculation->ejaculated_date
->diff($previousEjaculation->ejaculated_date)
->format('%a日 %h時間 %i分');
} else {
$ejaculatedSpan = null;
}
return view('ejaculation.show')->with(compact('user', 'ejaculation', 'ejaculatedSpan'));
} }
public function edit() public function edit($id)
{ {
// TODO: not implemented $ejaculation = Ejaculation::findOrFail($id);
$this->authorize('edit', $ejaculation);
return view('ejaculation.edit')->with(compact('ejaculation'));
} }
public function update() public function update(Request $request, $id)
{ {
// TODO: not implemented $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',
'link' => 'nullable|url|max:2000',
'tags' => 'nullable|string',
])->after(function ($validator) use ($id, $request, $inputs) {
// 日時の重複チェック
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', '既にこの日時にチェックインしているため、登録できません。');
}
}
});
if ($validator->fails()) {
return redirect()->route('checkin.edit', ['id' => $id])->withErrors($validator)->withInput();
}
$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
])->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 destroy() public function destroy($id)
{ {
// TODO: not implemented $ejaculation = Ejaculation::findOrFail($id);
$this->authorize('edit', $ejaculation);
$user = User::findOrFail($ejaculation->user_id);
$ejaculation->tags()->detach();
$ejaculation->delete();
return redirect()->route('user.profile', ['name' => $user->name])->with('status', '削除しました。');
} }
} }

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Ejaculation; use App\Ejaculation;
use App\Information;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@@ -26,54 +27,55 @@ class HomeController extends Controller
*/ */
public function index() public function index()
{ {
if (Auth::check()) { $informations = Information::query()
$ejaculations = Ejaculation::select(DB::raw(<<<'SQL' ->select('id', 'category', 'pinned', 'title', 'created_at')
to_char(ejaculated_date, 'YYYY/MM/DD HH24:MI') AS ejaculated_date, ->orderByDesc('pinned')
note, ->orderByDesc('created_at')
is_private, ->take(3)
to_char(lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC), 'YYYY/MM/DD HH24:MI') AS before_date, ->get();
to_char(ejaculated_date - (lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC)), 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span $categories = Information::CATEGORIES;
SQL
))
->where(['user_id' => Auth::id()])
->orderBy('ejaculated_date', 'desc')
->limit(9)
->get();
// 現在のオナ禁セッションの経過時間 if (Auth::check()) {
if (count($ejaculations) > 0) { // チェックイン動向グラフ用のデータ取得
$currentSession = Carbon::parse($ejaculations[0]['ejaculated_date']) $groupByDay = Ejaculation::select(DB::raw(
->diff(Carbon::now()) <<<'SQL'
->format('%d日 %h時間 %i分'); to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
} else { count(*) AS "count"
$currentSession = null; 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' $publicLinkedEjaculations = Ejaculation::join('users', 'users.id', '=', 'ejaculations.user_id')
SELECT ->where('users.is_protected', false)
to_char(avg(span), 'FMDDD日 FMHH24時間 FMMI分') AS average, ->where('ejaculations.is_private', false)
to_char(max(span), 'FMDDD日 FMHH24時間 FMMI分') AS longest, ->where('ejaculations.link', '<>', '')
to_char(min(span), 'FMDDD日 FMHH24時間 FMMI分') AS shortest, ->orderBy('ejaculations.ejaculated_date', 'desc')
to_char(sum(span), 'FMDDD日 FMHH24時間 FMMI分') AS total_times, ->select('ejaculations.*')
count(*) AS total_checkins ->with('user', 'tags')
FROM ->withLikes()
( ->take(10)
SELECT ->get();
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()]);
return view('home')->with(compact('ejaculations', 'currentSession', 'summary')); return view('home')->with(compact('informations', 'categories', 'globalEjaculationCounts', 'publicLinkedEjaculations'));
} else { } 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,51 @@
<?php
namespace App\Http\Controllers;
use App\Ejaculation;
use App\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class SearchController extends Controller
{
public function index(Request $request)
{
$inputs = $request->validate([
'q' => 'required'
]);
$results = Ejaculation::query()
->whereHas('tags', function ($query) use ($inputs) {
$query->where('name', 'like', "%{$inputs['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'
]);
$results = Tag::query()
->where('name', 'like', "%{$inputs['q']}%")
->paginate(50)
->appends($inputs);
return view('search.relatedTag')->with(compact('inputs', 'results'));
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace App\Http\Controllers;
use App\DeactivatedUser;
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 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,24 @@
<?php
namespace App\Http\Controllers;
use App\Ejaculation;
use Illuminate\Http\Request;
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', '<>', '')
->orderBy('ejaculations.ejaculated_date', 'desc')
->select('ejaculations.*')
->with('user', 'tags')
->withLikes()
->paginate(21);
return view('timeline.public')->with(compact('ejaculations'));
}
}

View File

@@ -11,7 +11,10 @@ use Illuminate\Support\Facades\DB;
class UserController extends Controller class UserController extends Controller
{ {
// public function redirectMypage()
{
return redirect()->route('user.profile', ['name' => auth()->user()->name]);
}
public function profile($name) public function profile($name)
{ {
@@ -21,10 +24,14 @@ class UserController extends Controller
} }
// チェックインの取得 // チェックインの取得
$query = Ejaculation::select(DB::raw(<<<'SQL' $query = Ejaculation::select(DB::raw(
to_char(ejaculated_date, 'YYYY/MM/DD HH24:MI') AS ejaculated_date, <<<'SQL'
id,
ejaculated_date,
note, note,
is_private, is_private,
is_too_sensitive,
link,
to_char(lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC), 'YYYY/MM/DD HH24:MI') AS before_date, 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 to_char(ejaculated_date - (lead(ejaculated_date, 1, NULL) OVER (ORDER BY ejaculated_date DESC)), 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
SQL SQL
@@ -34,39 +41,151 @@ SQL
$query = $query->where('is_private', false); $query = $query->where('is_private', false);
} }
$ejaculations = $query->orderBy('ejaculated_date', 'desc') $ejaculations = $query->orderBy('ejaculated_date', 'desc')
->with('tags')
->withLikes()
->paginate(20); ->paginate(20);
// 現在のオナ禁セッションの経過時間 // よく使っているタグ
if (count($ejaculations) > 0) { $tagsQuery = DB::table('ejaculations')
$currentSession = Carbon::parse($ejaculations[0]['ejaculated_date']) ->join('ejaculation_tag', 'ejaculations.id', '=', 'ejaculation_tag.ejaculation_id')
->diff(Carbon::now()) ->join('tags', 'ejaculation_tag.tag_id', '=', 'tags.id')
->format('%d日 %h時間 %i分'); ->selectRaw('tags.name, count(*) as count')
} else { ->where('ejaculations.user_id', $user->id);
$currentSession = null; 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();
return view('user.profile')->with(compact('user', 'ejaculations', 'tags'));
}
public function stats($name)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
} }
// 概況欄のデータ取得 $dateUntil = now()->addMonth()->startOfMonth();
$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', 'currentSession', 'summary')); $groupByDay = Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
count(*) AS "count"
SQL
))
->where('user_id', $user->id)
->where('ejaculated_date', '<', $dateUntil)
->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
->get();
$groupByHour = Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'HH24') AS "hour",
count(*) AS "count"
SQL
))
->where('user_id', $user->id)
->where('ejaculated_date', '<', $dateUntil)
->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;
}
$graphData = [
'dailySum' => $dailySum,
'dowSum' => $dowSum,
'monthlySum' => $monthlySum,
'yearlyKey' => array_keys($yearlySum),
'yearlySum' => array_values($yearlySum),
'hourlyKey' => array_keys($hourlySum),
'hourlySum' => array_values($hourlySum),
];
return view('user.stats')->with(compact('user', 'graphData'));
}
public function okazu($name)
{
$user = User::where('name', $name)->first();
if (empty($user)) {
abort(404);
}
// チェックインの取得
$query = Ejaculation::select(DB::raw(
<<<'SQL'
id,
ejaculated_date,
note,
is_private,
is_too_sensitive,
link,
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', $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')
->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'));
} }
} }

View File

@@ -18,6 +18,7 @@ class Kernel extends HttpKernel
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class, \App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
]; ];
/** /**
@@ -34,9 +35,15 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class, \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\NormalizeLineEnding::class,
], ],
// 現時点では内部APIしかないので、認証の手間を省くためにステートフルにしている。
'api' => [ 'api' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
'throttle:60,1', 'throttle:60,1',
'bindings', 'bindings',
], ],

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) public function handle($request, Closure $next, $guard = null)
{ {
if (Auth::guard($guard)->check()) { if (Auth::guard($guard)->check()) {
return redirect('/home'); return redirect()->route('home');
} }
return $next($request); return $next($request);

View File

@@ -0,0 +1,29 @@
<?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
*/
protected $proxies = '**';
/**
* The current proxy header mappings.
*
* @var array
*/
protected $headers = [
Request::HEADER_FORWARDED => 'FORWARDED',
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
];
}

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,79 @@
<?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.');
}
$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 = DB::select(<<<'SQL'
SELECT
avg(span) AS average
FROM
(
SELECT
extract(epoch from 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
LIMIT
30
) AS temp
SQL
, ['user_id' => $user->id]);
$summary = DB::select(<<<'SQL'
SELECT
max(span) AS longest,
min(span) AS shortest,
sum(span) AS total_times,
count(*) AS total_checkins
FROM
(
SELECT
extract(epoch from 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]);
$view->with(compact('latestEjaculation', 'currentSession', 'average', 'summary'));
}
}

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,71 @@
<?php
namespace App\Listeners;
use App\Events\LinkDiscovered;
use App\Metadata;
use App\MetadataResolver\MetadataResolver;
use App\Tag;
use App\Utilities\Formatter;
use GuzzleHttp\Exception\TransferException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
class LinkCollector
{
/** @var Formatter */
private $formatter;
/** @var MetadataResolver */
private $metadataResolver;
/**
* Create the event listener.
*
* @param Formatter $formatter
* @param MetadataResolver $metadataResolver
*/
public function __construct(Formatter $formatter, MetadataResolver $metadataResolver)
{
$this->formatter = $formatter;
$this->metadataResolver = $metadataResolver;
}
/**
* Handle the event.
*
* @param LinkDiscovered $event
* @return void
*/
public function handle(LinkDiscovered $event)
{
// URLの正規化
$url = $this->formatter->normalizeUrl($event->url);
// 無かったら取得
// TODO: ある程度古かったら再取得とかありだと思う
$metadata = Metadata::find($url);
if ($metadata == null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
try {
$resolved = $this->metadataResolver->resolve($url);
$metadata = Metadata::updateOrCreate(['url' => $url], [
'title' => $resolved->title,
'description' => $resolved->description,
'image' => $resolved->image,
'expires_at' => $resolved->expires_at
]);
$tagIds = [];
foreach ($resolved->tags as $tagName) {
$tag = Tag::firstOrCreate(['name' => $tagName]);
$tagIds[] = $tag->id;
}
$metadata->tags()->sync($tagIds);
} catch (TransferException $e) {
// 何らかの通信エラーによってメタデータの取得に失敗した時、とりあえずエラーログにURLを残す
Log::error(self::class . ': メタデータの取得に失敗 URL=' . $url);
report($e);
}
}
}
}

22
app/Metadata.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
namespace App;
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'];
public function tags()
{
return $this->belongsToMany(Tag::class)->withTimestamps();
}
}

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,39 @@
<?php
namespace App\MetadataResolver;
use Carbon\Carbon;
use GuzzleHttp\Client;
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);
$metadata = $this->ogpResolver->parse((string) $res->getBody());
// 画像URLから有効期限の起点を拾う
parse_str(parse_url($metadata->image, PHP_URL_QUERY), $params);
if (empty($params['px-time'])) {
throw new \RuntimeException('Parameter "px-time" not found. Image=' . $metadata->image . ' Source=' . $url);
}
$metadata->expires_at = Carbon::createFromTimestamp($params['px-time'])->addHour(1);
return $metadata;
}
}

View File

@@ -0,0 +1,129 @@
<?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));
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,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,40 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
class FC2ContentsResolver 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);
$thumbnailNode = $xpath->query('//*[@class="main_thum_img"]/a')->item(0);
if ($thumbnailNode) {
$metadata->image = preg_replace('~^http:~', 'https:', $thumbnailNode->getAttribute('href'));
}
return $metadata;
}
}

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,105 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
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
{
$res = $this->client->get($url);
$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($crawler->filter('.box-rank+table+div+div')->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('.box-rank+table a:not([href="#review"])')->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('.area-bskt table a:not([href="#review"])')->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 . $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,51 @@
<?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'])) {
foreach ($json['content']['attributes']['tags']['children'] as $tag) {
$metadata->tags[] = preg_replace('/\s/', '_', $tag['data']['name']);
}
}
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,26 @@
<?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 = [];
}

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]{2,}~' => NarouResolver::class,
'~ci-en\.jp/creator/\d+/article/\d+~' => CienResolver::class,
'~www\.plurk\.com\/p\/.*~' => PlurkResolver::class,
'~(adult\.)?contents\.fc2\.com\/article_search\.php\?id=\d+~' => FC2ContentsResolver::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,
];
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,63 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
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']) &&
!ends_with($data['thumbnailUrl'], '.gif') &&
!ends_with($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,59 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
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)->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,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,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,10 @@
namespace App\Providers; namespace App\Providers;
use App\MetadataResolver\MetadataResolver;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Parsedown;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
@@ -13,7 +16,9 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
// Blade::directive('parsedown', function ($expression) {
return "<?php echo app('parsedown')->text($expression); ?>";
});
} }
/** /**
@@ -23,6 +28,11 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function register() public function register()
{ {
// $this->app->singleton(MetadataResolver::class, function ($app) {
return new MetadataResolver();
});
$this->app->singleton('parsedown', function () {
return Parsedown::instance();
});
} }
} }

View File

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

View File

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

View File

@@ -2,8 +2,8 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider class EventServiceProvider extends ServiceProvider
{ {
@@ -13,9 +13,9 @@ class EventServiceProvider extends ServiceProvider
* @var array * @var array
*/ */
protected $listen = [ protected $listen = [
'App\Events\Event' => [ 'App\Events\LinkDiscovered' => [
'App\Listeners\EventListener', '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; namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider 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()
{
//
}
}

22
app/Tag.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
//
protected $fillable = [
'name'
];
protected $visible = [
'name'
];
public function ejaculations()
{
return $this->belongsToMany('App\Ejaculation')->withTimestamps();
}
}

View File

@@ -2,8 +2,9 @@
namespace App; namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Auth;
class User extends Authenticatable class User extends Authenticatable
{ {
@@ -19,6 +20,7 @@ class User extends Authenticatable
'is_protected', 'accept_analytics', 'is_protected', 'accept_analytics',
'display_name', 'description', 'display_name', 'description',
'twitter_id', 'twitter_name', 'twitter_id', 'twitter_name',
'private_likes',
]; ];
/** /**
@@ -29,4 +31,35 @@ class User extends Authenticatable
protected $hidden = [ protected $hidden = [
'password', 'remember_token', 'password', 'remember_token',
]; ];
/**
* このユーザのメールアドレスから、Gravatarの画像URLを生成します。
* @param int $size 画像サイズ
* @return string Gravatar 画像URL
*/
public function getProfileImageUrl($size = 30): string
{
$hash = md5(strtolower(trim($this->email)));
return '//www.gravatar.com/avatar/' . $hash . '?s=' . $size . '&d=retro';
}
/**
* このユーザがログイン中のユーザ本人であるかをチェックします。
* @return bool 本人かどうか
*/
public function isMe()
{
return Auth::check() && $this->id === Auth::user()->id;
}
public function ejaculations()
{
return $this->hasMany(Ejaculation::class);
}
public function likes()
{
return $this->hasMany(Like::class);
}
} }

View File

@@ -0,0 +1,78 @@
<?php
namespace App\Utilities;
use Misd\Linkify\Linkify;
class Formatter
{
/** @var Linkify */
private $linkify;
public function __construct()
{
$this->linkify = new Linkify();
}
/**
* 通算秒数を日数と時分にフォーマットします。
* @param int|float $value 通算秒数
* @return string "xx日 xx時間 xx分" 形式でフォーマットされた文字列
*/
public function formatInterval($value)
{
$days = floor($value / 86400);
$hours = floor($value % 86400 / 3600);
$minutes = floor($value % 3600 / 60);
return "{$days}{$hours}時間 {$minutes}";
}
/**
* テキスト内のURLをHTMLのリンクに置き換えます。
* @param string $text テキスト
* @return string URLをリンクに置き換えた文字列
*/
public function linkify($text)
{
return $this->linkify->processUrls($text, ['attr' => ['target' => '_blank', 'rel' => 'noopener']]);
}
/**
* URLを正規化します。
* @param string $url URL
* @return string 正規化されたURL
*/
public function normalizeUrl($url)
{
// Decode
$url = urldecode($url);
// Remove Hashbang
$url = preg_replace('~/#!/~u', '/', $url);
// Sort query parameters
$parts = parse_url($url);
if (!empty($parts['query'])) {
// Remove query parameters
$url = str_replace_last('?' . $parts['query'], '', $url);
if (!empty($parts['fragment'])) {
// Remove fragment identifier
$url = str_replace_last('#' . $parts['fragment'], '', $url);
} else {
// "http://example.com/?query#" の場合 $parts['fragment'] は unset になるので、個別に判定して除去する必要がある
$url = preg_replace('/#\z/u', '', $url);
}
parse_str($parts['query'], $params);
ksort($params);
$url = $url . '?' . http_build_query($params);
if (!empty($parts['fragment'])) {
$url .= '#' . $parts['fragment'];
}
}
return $url;
}
}

View File

@@ -5,14 +5,28 @@
"license": "MIT", "license": "MIT",
"type": "project", "type": "project",
"require": { "require": {
"php": ">=5.6.4", "php": ">=7.1.0",
"laravel/framework": "5.4.*", "anhskohbo/no-captcha": "^3.0",
"laravel/tinker": "~1.0" "doctrine/dbal": "^2.9",
"fideloper/proxy": "~3.3",
"guzzlehttp/guzzle": "^6.3",
"jakeasmith/http_build_url": "^1.0",
"laravel/framework": "5.5.*",
"laravel/tinker": "~1.0",
"misd/linkify": "^1.1",
"staudenmeir/eloquent-eager-limit": "^1.0",
"symfony/css-selector": "^4.3",
"symfony/dom-crawler": "^4.3"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.1",
"barryvdh/laravel-ide-helper": "^2.5",
"filp/whoops": "~2.0",
"friendsofphp/php-cs-fixer": "^2.14",
"fzaninotto/faker": "~1.4", "fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*", "mockery/mockery": "~1.0",
"phpunit/phpunit": "~5.7" "phpunit/phpunit": "~6.0",
"symfony/thanks": "^1.0"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@@ -29,18 +43,20 @@
}, },
"scripts": { "scripts": {
"post-root-package-install": [ "post-root-package-install": [
"php -r \"file_exists('.env') || copy('.env.example', '.env');\"" "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
], ],
"post-create-project-cmd": [ "post-create-project-cmd": [
"php artisan key:generate" "@php artisan key:generate"
], ],
"post-install-cmd": [ "post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postInstall", "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"php artisan optimize" "@php artisan package:discover"
], ],
"post-update-cmd": [ "fix": [
"Illuminate\\Foundation\\ComposerScripts::postUpdate", "php-cs-fixer fix --config=.php_cs.dist"
"php artisan optimize" ],
"test": [
"phpunit"
] ]
}, },
"config": { "config": {

4373
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -176,6 +176,7 @@ return [
// App\Providers\BroadcastServiceProvider::class, // App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
App\Providers\ViewComposerServiceProvider::class,
], ],
@@ -226,6 +227,7 @@ return [
'Validator' => Illuminate\Support\Facades\Validator::class, 'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class, 'View' => Illuminate\Support\Facades\View::class,
'Formatter' => App\Facades\Formatter::class,
], ],
]; ];

View File

@@ -0,0 +1,12 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Ejaculation;
use Faker\Generator as Faker;
$factory->define(Ejaculation::class, function (Faker $faker) {
return [
'ejaculated_date' => $faker->date('Y-m-d H:i:s'),
'note' => $faker->text,
];
});

View File

@@ -0,0 +1,10 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use Faker\Generator as Faker;
$factory->define(App\Like::class, function (Faker $faker) {
return [
//
];
});

View File

@@ -1,24 +0,0 @@
<?php
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
|
*/
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});

View File

@@ -0,0 +1,21 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'name' => substr($faker->userName, 0, 15),
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
'display_name' => substr($faker->name, 0, 20),
'is_protected' => false,
'accept_analytics' => false,
'private_likes' => false,
];
});
$factory->state(App\User::class, 'protected', [
'is_protected' => true,
]);

View File

@@ -1,8 +1,8 @@
<?php <?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration class CreateUsersTable extends Migration
{ {

View File

@@ -1,8 +1,8 @@
<?php <?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePasswordResetsTable extends Migration class CreatePasswordResetsTable extends Migration
{ {

View File

@@ -1,8 +1,8 @@
<?php <?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateEjaculationsTable extends Migration class CreateEjaculationsTable extends Migration
{ {

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateInformationTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('information', function (Blueprint $table) {
$table->increments('id');
$table->integer('category');
$table->boolean('pinned')->default(false);
$table->text('title');
$table->text('content');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('information');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddLinkToEjaculations extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('ejaculations', function (Blueprint $table) {
$table->string('link')->default('');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('ejaculations', function (Blueprint $table) {
$table->removeColumn('link');
});
}
}

View File

@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTagsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('ejaculation_tag', function (Blueprint $table) {
$table->increments('id');
$table->integer('ejaculation_id')->index();
$table->integer('tag_id')->index();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tags');
Schema::dropIfExists('ejaculation_tag');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateMetadataTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('metadata', function (Blueprint $table) {
$table->string('url');
$table->string('title');
$table->string('description');
$table->string('image');
$table->timestamps();
$table->index('url');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('metadata');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class RecreateMetadataTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::dropIfExists('metadata');
Schema::create('metadata', function (Blueprint $table) {
$table->text('url');
$table->text('title');
$table->text('description');
$table->text('image');
$table->timestamps();
$table->index('url');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('metadata');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ChangeLinkOnEjaculations extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('ejaculations', function (Blueprint $table) {
$table->text('link')->default('')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('ejaculations', function (Blueprint $table) {
$table->string('link')->default('')->change();
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddExpiresOnMetadata extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('metadata', function (Blueprint $table) {
$table->timestamp('expires_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('metadata', function (Blueprint $table) {
$table->removeColumn('expires_at');
});
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddBioAndUrlToUsers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('bio', 160)->default('');
$table->text('url')->default('');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('bio');
$table->dropColumn('url');
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsAdminToUsers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('is_admin')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('is_admin');
});
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateLikesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('likes', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->index();
$table->integer('ejaculation_id')->index();
$table->timestamps();
$table->unique(['user_id', 'ejaculation_id']);
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('ejaculation_id')->references('id')->on('ejaculations')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('likes');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPrivateLikesToUsers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('private_likes')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('private_likes');
});
}
}

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