Merge pull request #45 from shikorism/develop

Release 20190117.0100
This commit is contained in:
shibafu 2019-01-17 01:05:04 +09:00 committed by GitHub
commit 09482ca2c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 960 additions and 101 deletions

View File

@ -5,12 +5,12 @@ APP_DEBUG=true
APP_LOG_LEVEL=debug APP_LOG_LEVEL=debug
APP_URL=http://localhost APP_URL=http://localhost
DB_CONNECTION=mysql DB_CONNECTION=pgsql
DB_HOST=127.0.0.1 DB_HOST=db
DB_PORT=3306 DB_PORT=5432
DB_DATABASE=homestead DB_DATABASE=tissue
DB_USERNAME=homestead DB_USERNAME=tissue
DB_PASSWORD=secret DB_PASSWORD=tissue
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
CACHE_DRIVER=file CACHE_DRIVER=file
@ -35,3 +35,8 @@ 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

4
.gitignore vendored
View File

@ -10,4 +10,6 @@ Homestead.yaml
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
.env .env
*.iml *.iml
.php_cs
.php_cs.cache

26
.php_cs.dist Normal file
View File

@ -0,0 +1,26 @@
<?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
])
->setFinder(
\PhpCsFixer\Finder::create()
->exclude('bootstrap/cache')
->exclude('resources/views')
->exclude('storage')
->exclude('vendor')
->exclude('node_modules')
->in(__DIR__)
);

View File

@ -3,12 +3,19 @@ FROM php:7.1-apache
ENV APACHE_DOCUMENT_ROOT /var/www/html/public ENV APACHE_DOCUMENT_ROOT /var/www/html/public
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y git libpq-dev \ && apt-get install -y git libpq-dev unzip \
&& docker-php-ext-install pdo_pgsql \ && docker-php-ext-install pdo_pgsql \
&& pecl install xdebug \
&& curl -sS https://getcomposer.org/installer | php \ && curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer \ && mv composer.phar /usr/local/bin/composer \
&& sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \ && sed -ri -e 's!/var/www/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 \ && sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \
&& a2enmod rewrite && a2enmod rewrite
COPY dist/bin /usr/local/bin/
COPY dist/php.d /usr/local/etc/php/php.d/
ENTRYPOINT ["tissue-entrypoint.sh"]
CMD ["apache2-foreground"]
WORKDIR /var/www/html WORKDIR /var/www/html

View File

@ -30,6 +30,8 @@ class Ejaculation extends Model
public function textTags() public function textTags()
{ {
return implode(' ', $this->tags->map(function ($v) { return $v->name; })->all()); return implode(' ', $this->tags->map(function ($v) {
return $v->name;
})->all());
} }
} }

View File

@ -2,9 +2,9 @@
namespace App\Events; namespace App\Events;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class LinkDiscovered class LinkDiscovered
{ {

View File

@ -10,4 +10,4 @@ class Formatter extends Facade
{ {
return \App\Utilities\Formatter::class; return \App\Utilities\Formatter::class;
} }
} }

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',
'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,14 +2,14 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Ejaculation;
use App\Events\LinkDiscovered; use App\Events\LinkDiscovered;
use App\Tag; use App\Tag;
use App\User; use App\User;
use Carbon\Carbon; use Carbon\Carbon;
use Validator;
use App\Ejaculation;
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
{ {
@ -104,6 +104,7 @@ class EjaculationController extends Controller
public function edit($id) public function edit($id)
{ {
$ejaculation = Ejaculation::findOrFail($id); $ejaculation = Ejaculation::findOrFail($id);
return view('ejaculation.edit')->with(compact('ejaculation')); return view('ejaculation.edit')->with(compact('ejaculation'));
} }
@ -133,7 +134,7 @@ class EjaculationController extends Controller
}); });
if ($validator->fails()) { if ($validator->fails()) {
return redirect()->route('checkin')->withErrors($validator)->withInput(); return redirect()->route('checkin.edit', ['id' => $id])->withErrors($validator)->withInput();
} }
$ejaculation->fill([ $ejaculation->fill([
@ -166,6 +167,7 @@ class EjaculationController extends Controller
$user = User::findOrFail($ejaculation->user_id); $user = User::findOrFail($ejaculation->user_id);
$ejaculation->tags()->detach(); $ejaculation->tags()->detach();
$ejaculation->delete(); $ejaculation->delete();
return redirect()->route('user.profile', ['name' => $user->name])->with('status', '削除しました。'); return redirect()->route('user.profile', ['name' => $user->name])->with('status', '削除しました。');
} }
} }

View File

@ -14,6 +14,7 @@ class InfoController extends Controller
->orderByDesc('pinned') ->orderByDesc('pinned')
->orderByDesc('created_at') ->orderByDesc('created_at')
->paginate(20); ->paginate(20);
return view('info.index')->with([ return view('info.index')->with([
'informations' => $informations, 'informations' => $informations,
'categories' => Information::CATEGORIES 'categories' => Information::CATEGORIES
@ -23,6 +24,7 @@ class InfoController extends Controller
public function show($id) public function show($id)
{ {
$information = Information::findOrFail($id); $information = Information::findOrFail($id);
return view('info.show')->with([ return view('info.show')->with([
'info' => $information, 'info' => $information,
'category' => Information::CATEGORIES[$information->category] 'category' => Information::CATEGORIES[$information->category]

View File

@ -38,4 +38,4 @@ class SearchController extends Controller
return view('search.relatedTag')->with(compact('inputs', 'results')); return view('search.relatedTag')->with(compact('inputs', 'results'));
} }
} }

View File

@ -21,7 +21,8 @@ class UserController extends Controller
} }
// チェックインの取得 // チェックインの取得
$query = Ejaculation::select(DB::raw(<<<'SQL' $query = Ejaculation::select(DB::raw(
<<<'SQL'
id, id,
ejaculated_date, ejaculated_date,
note, note,
@ -63,7 +64,8 @@ SQL
abort(404); abort(404);
} }
$groupByDay = Ejaculation::select(DB::raw(<<<'SQL' $groupByDay = Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date", to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
count(*) AS "count" count(*) AS "count"
SQL SQL
@ -73,7 +75,8 @@ SQL
->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) ->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
->get(); ->get();
$groupByHour = Ejaculation::select(DB::raw(<<<'SQL' $groupByHour = Ejaculation::select(DB::raw(
<<<'SQL'
to_char(ejaculated_date, 'HH24') AS "hour", to_char(ejaculated_date, 'HH24') AS "hour",
count(*) AS "count" count(*) AS "count"
SQL SQL
@ -133,7 +136,8 @@ SQL
} }
// チェックインの取得 // チェックインの取得
$query = Ejaculation::select(DB::raw(<<<'SQL' $query = Ejaculation::select(DB::raw(
<<<'SQL'
id, id,
ejaculated_date, ejaculated_date,
note, note,

View File

@ -58,4 +58,4 @@ SQL
$view->with(compact('latestEjaculation', 'currentSession', 'summary')); $view->with(compact('latestEjaculation', 'currentSession', 'summary'));
} }
} }

View File

@ -7,8 +7,8 @@ use App\Metadata;
use App\MetadataResolver\MetadataResolver; use App\MetadataResolver\MetadataResolver;
use App\Utilities\Formatter; use App\Utilities\Formatter;
use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Exception\TransferException;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class LinkCollector class LinkCollector
@ -43,14 +43,14 @@ class LinkCollector
// 無かったら取得 // 無かったら取得
// TODO: ある程度古かったら再取得とかありだと思う // TODO: ある程度古かったら再取得とかありだと思う
$metadata = Metadata::find($url); $metadata = Metadata::find($url);
if ($metadata == null) { if ($metadata == null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
try { try {
$resolved = $this->metadataResolver->resolve($url); $resolved = $this->metadataResolver->resolve($url);
Metadata::create([ Metadata::updateOrCreate(['url' => $url], [
'url' => $url,
'title' => $resolved->title, 'title' => $resolved->title,
'description' => $resolved->description, 'description' => $resolved->description,
'image' => $resolved->image 'image' => $resolved->image,
'expires_at' => $resolved->expires_at
]); ]);
} catch (TransferException $e) { } catch (TransferException $e) {
// 何らかの通信エラーによってメタデータの取得に失敗した時、とりあえずエラーログにURLを残す // 何らかの通信エラーによってメタデータの取得に失敗した時、とりあえずエラーログにURLを残す

View File

@ -10,6 +10,8 @@ class Metadata extends Model
protected $primaryKey = 'url'; protected $primaryKey = 'url';
protected $keyType = 'string'; protected $keyType = 'string';
protected $fillable = ['url', 'title', 'description', 'image']; protected $fillable = ['url', 'title', 'description', 'image', 'expires_at'];
protected $visible = ['url', 'title', 'description', 'image']; protected $visible = ['url', 'title', 'description', 'image', 'expires_at'];
protected $dates = ['created_at', 'updated_at', 'expires_at'];
} }

View File

@ -2,8 +2,6 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use Illuminate\Support\Facades\Log;
class DLsiteResolver implements Resolver class DLsiteResolver implements Resolver
{ {
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
@ -14,9 +12,10 @@ class DLsiteResolver implements Resolver
$ogpResolver = new OGPResolver(); $ogpResolver = new OGPResolver();
$metadata = $ogpResolver->parse($res->getBody()); $metadata = $ogpResolver->parse($res->getBody());
$metadata->image = str_replace("img_sam.jpg", "img_main.jpg", $metadata->image); $metadata->image = str_replace("img_sam.jpg", "img_main.jpg", $metadata->image);
return $metadata; return $metadata;
} else { } else {
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -0,0 +1,42 @@
<?php
namespace App\MetadataResolver;
use Illuminate\Support\Facades\Log;
class FantiaResolver implements Resolver
{
public function resolve(string $url): Metadata
{
preg_match("~\d+~", $url, $match);
$postId = $match[0];
$client = new \GuzzleHttp\Client();
$res = $client->get($url);
if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver();
$metadata = $ogpResolver->parse($res->getBody());
$dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));
$xpath = new \DOMXPath($dom);
$node = $xpath->query("//meta[@property='twitter:image']")->item(0);
$ogpUrl = $node->getAttribute('content');
// 投稿に画像がない場合ogp.jpgでない場合のみ大きい画像に変換する
if ($ogpUrl != "http://fantia.jp/images/ogp.jpg") {
preg_match("~https://fantia\.s3\.amazonaws\.com/uploads/post/file/{$postId}/ogp_(.*?)\.(jpg|png)~", $ogpUrl, $match);
$uuid = $match[1];
$extension = $match[2];
// 大きい画像に変換
$metadata->image = "https://c.fantia.jp/uploads/post/file/{$postId}/main_{$uuid}.{$extension}";
}
return $metadata;
} else {
throw new \RuntimeException("{$res->getStatusCode()}: $url");
}
}
}

View File

@ -54,4 +54,4 @@ class IwaraResolver implements Resolver
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -27,4 +27,4 @@ class KomifloResolver implements Resolver
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -26,4 +26,4 @@ class MelonbooksResolver implements Resolver
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -2,9 +2,13 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use Carbon\Carbon;
class Metadata class Metadata
{ {
public $title = ''; public $title = '';
public $description = ''; public $description = '';
public $image = ''; public $image = '';
} /** @var Carbon|null */
public $expires_at = null;
}

View File

@ -12,6 +12,8 @@ class MetadataResolver implements Resolver
'~ec\.toranoana\.jp/tora_r/ec/item/.*~' => ToranoanaResolver::class, '~ec\.toranoana\.jp/tora_r/ec/item/.*~' => ToranoanaResolver::class,
'~iwara\.tv/videos/.*~' => IwaraResolver::class, '~iwara\.tv/videos/.*~' => IwaraResolver::class,
'~www\.dlsite\.com/.*/work/=/product_id/..\d+\.html~' => DLsiteResolver::class, '~www\.dlsite\.com/.*/work/=/product_id/..\d+\.html~' => DLsiteResolver::class,
'~www\.pixiv\.net/member_illust\.php\?illust_id=\d+~' => PixivResolver::class,
'~fantia\.jp/posts/\d+~' => FantiaResolver::class,
'/.*/' => OGPResolver::class '/.*/' => OGPResolver::class
]; ];
@ -19,11 +21,12 @@ class MetadataResolver implements Resolver
{ {
foreach ($this->rules as $pattern => $class) { foreach ($this->rules as $pattern => $class) {
if (preg_match($pattern, $url) === 1) { if (preg_match($pattern, $url) === 1) {
$resolver = new $class; $resolver = new $class();
return $resolver->resolve($url); return $resolver->resolve($url);
} }
} }
throw new \UnexpectedValueException('URL not matched.'); throw new \UnexpectedValueException('URL not matched.');
} }
} }

View File

@ -21,4 +21,4 @@ class NicoSeigaResolver implements Resolver
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -37,4 +37,4 @@ class NijieResolver implements Resolver
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -41,6 +41,7 @@ class OGPResolver implements Resolver
} }
} }
} }
return ''; return '';
} }
} }

View File

@ -0,0 +1,93 @@
<?php
namespace App\MetadataResolver;
class PixivResolver implements Resolver
{
/**
* サムネイル画像 URL から最大長辺 1200px の画像 URL に変換する
*
* @param string $thumbnailUrl サムネイル画像 URL
* @return string 1200px の画像 URL
*/
public function thumbnailToMasterUrl(string $thumbnailUrl): string
{
$temp = str_replace("/c/128x128", "", $thumbnailUrl);
$largeUrl = str_replace("square1200.jpg", "master1200.jpg", $temp);
return $largeUrl;
}
/**
* 直リン可能な 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
{
preg_match("~illust_id=(\d+)~", parse_url($url)["query"], $match);
$illustId = $match[1];
// 漫画ページかつページ数あり
if (strpos(parse_url($url)["query"], "mode=manga_big") && strpos(parse_url($url)["query"], "page=")) {
preg_match("~page=(\d+)~", parse_url($url)["query"], $match);
$page = $match[1];
// 未ログインでは漫画ページを開けないため、URL を作品ページに変換する
$url = str_replace("mode=manga_big", "mode=medium", $url);
$client = new \GuzzleHttp\Client();
$res = $client->get($url);
if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver();
$metadata = $ogpResolver->parse($res->getBody());
preg_match("~https://i\.pximg\.net/c/128x128/img-master/img/\d{4}/\d{2}/\d{2}/\d{2}/\d{2}/\d{2}/{$illustId}_p0_square1200\.jpg~", $res->getBody(), $match);
$illustThumbnailUrl = $match[0];
$illustUrl = $this->thumbnailToMasterUrl($illustThumbnailUrl);
// 指定ページに変換
$illustUrl = str_replace("p0_master", "p{$page}_master", $illustUrl);
$metadata->image = $this->proxize($illustUrl);
return $metadata;
} else {
throw new \RuntimeException("{$res->getStatusCode()}: $url");
}
} else {
$client = new \GuzzleHttp\Client();
$res = $client->get($url);
if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver();
$metadata = $ogpResolver->parse($res->getBody());
// OGP がデフォルト画像であるようならなんとかして画像を取得する
if (strpos($metadata->image, "pixiv_logo.gif") || strpos($metadata->image, "pictures.jpg")) {
// 作品ページの場合のみ対応
if (strpos(parse_url($url)["query"], "mode=medium")) {
preg_match("~https://i\.pximg\.net/c/128x128/img-master/img/\d{4}/\d{2}/\d{2}/\d{2}/\d{2}/\d{2}/{$illustId}(_p0)?_square1200\.jpg~", $res->getBody(), $match);
$illustThumbnailUrl = $match[0];
$illustUrl = $this->thumbnailToMasterUrl($illustThumbnailUrl);
$metadata->image = $this->proxize($illustUrl);
}
}
return $metadata;
} else {
throw new \RuntimeException("{$res->getStatusCode()}: $url");
}
}
}
}

View File

@ -5,4 +5,4 @@ namespace App\MetadataResolver;
interface Resolver interface Resolver
{ {
public function resolve(string $url): Metadata; public function resolve(string $url): Metadata;
} }

View File

@ -14,9 +14,10 @@ class ToranoanaResolver implements Resolver
$res = $client->get($url, ['cookies' => $cookieJar]); $res = $client->get($url, ['cookies' => $cookieJar]);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $ogpResolver = new OGPResolver();
return $ogpResolver->parse($res->getBody()); return $ogpResolver->parse($res->getBody());
} else { } else {
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }
} }
} }

View File

@ -2,8 +2,8 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Support\Facades\Gate;
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
{ {

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
{ {

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

@ -2,8 +2,8 @@
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; use Illuminate\Support\Facades\Auth;
class User extends Authenticatable class User extends Authenticatable
@ -36,9 +36,10 @@ class User extends Authenticatable
* @param int $size 画像サイズ * @param int $size 画像サイズ
* @return string Gravatar 画像URL * @return string Gravatar 画像URL
*/ */
public function getProfileImageUrl($size = 30) : string public function getProfileImageUrl($size = 30): string
{ {
$hash = md5(strtolower(trim($this->email))); $hash = md5(strtolower(trim($this->email)));
return '//www.gravatar.com/avatar/' . $hash . '?s=' . $size; return '//www.gravatar.com/avatar/' . $hash . '?s=' . $size;
} }

View File

@ -24,6 +24,7 @@ class Formatter
$days = floor($value / 86400); $days = floor($value / 86400);
$hours = floor($value % 86400 / 3600); $hours = floor($value % 86400 / 3600);
$minutes = floor($value % 3600 / 60); $minutes = floor($value % 3600 / 60);
return "{$days}{$hours}時間 {$minutes}"; return "{$days}{$hours}時間 {$minutes}";
} }
@ -61,4 +62,4 @@ class Formatter
return $url; return $url;
} }
} }

View File

@ -6,6 +6,7 @@
"type": "project", "type": "project",
"require": { "require": {
"php": ">=7.0.0", "php": ">=7.0.0",
"anhskohbo/no-captcha": "^3.0",
"doctrine/dbal": "^2.9", "doctrine/dbal": "^2.9",
"fideloper/proxy": "~3.3", "fideloper/proxy": "~3.3",
"guzzlehttp/guzzle": "^6.3", "guzzlehttp/guzzle": "^6.3",
@ -16,6 +17,7 @@
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.1", "barryvdh/laravel-debugbar": "^3.1",
"filp/whoops": "~2.0", "filp/whoops": "~2.0",
"friendsofphp/php-cs-fixer": "^2.14",
"fzaninotto/faker": "~1.4", "fzaninotto/faker": "~1.4",
"mockery/mockery": "~1.0", "mockery/mockery": "~1.0",
"phpunit/phpunit": "~6.0", "phpunit/phpunit": "~6.0",

591
composer.lock generated
View File

@ -4,8 +4,67 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6ac4cd158b1f93a24e21fce57d4404c8", "content-hash": "9a0efd1b396f7a748eee3b98cbd7b6a6",
"packages": [ "packages": [
{
"name": "anhskohbo/no-captcha",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/anhskohbo/no-captcha.git",
"reference": "164715a2de0fded5979e7a9b7721785d72a4a7d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/anhskohbo/no-captcha/zipball/164715a2de0fded5979e7a9b7721785d72a4a7d3",
"reference": "164715a2de0fded5979e7a9b7721785d72a4a7d3",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.2",
"illuminate/support": "5.0.*|5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*",
"php": ">=5.5.5"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Anhskohbo\\NoCaptcha\\NoCaptchaServiceProvider"
],
"aliases": {
"NoCaptcha": "Anhskohbo\\NoCaptcha\\Facades\\NoCaptcha"
}
}
},
"autoload": {
"psr-4": {
"Anhskohbo\\NoCaptcha\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "anhskohbo",
"email": "anhskohbo@gmail.com"
}
],
"description": "No CAPTCHA reCAPTCHA For Laravel.",
"keywords": [
"captcha",
"laravel",
"laravel4",
"laravel5",
"no-captcha",
"recaptcha"
],
"time": "2018-08-27T02:16:31+00:00"
},
{ {
"name": "dnoegel/php-xdg-base-dir", "name": "dnoegel/php-xdg-base-dir",
"version": "0.1", "version": "0.1",
@ -2986,6 +3045,180 @@
], ],
"time": "2018-11-09T08:37:55+00:00" "time": "2018-11-09T08:37:55+00:00"
}, },
{
"name": "composer/semver",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5",
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"keywords": [
"semantic",
"semver",
"validation",
"versioning"
],
"time": "2016-08-30T16:08:34+00:00"
},
{
"name": "composer/xdebug-handler",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "dc523135366eb68f22268d069ea7749486458562"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562",
"reference": "dc523135366eb68f22268d069ea7749486458562",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Composer\\XdebugHandler\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "John Stevenson",
"email": "john-stevenson@blueyonder.co.uk"
}
],
"description": "Restarts a process without xdebug.",
"keywords": [
"Xdebug",
"performance"
],
"time": "2018-11-29T10:59:02+00:00"
},
{
"name": "doctrine/annotations",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"php": "^7.1"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "^6.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
],
"time": "2017-12-06T07:11:42+00:00"
},
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
"version": "1.1.0", "version": "1.1.0",
@ -3101,6 +3334,102 @@
], ],
"time": "2018-10-23T09:00:00+00:00" "time": "2018-10-23T09:00:00+00:00"
}, },
{
"name": "friendsofphp/php-cs-fixer",
"version": "v2.14.0",
"source": {
"type": "git",
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
"reference": "b788ea0af899cedc8114dca7db119c93b6685da2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/b788ea0af899cedc8114dca7db119c93b6685da2",
"reference": "b788ea0af899cedc8114dca7db119c93b6685da2",
"shasum": ""
},
"require": {
"composer/semver": "^1.4",
"composer/xdebug-handler": "^1.2",
"doctrine/annotations": "^1.2",
"ext-json": "*",
"ext-tokenizer": "*",
"php": "^5.6 || ^7.0",
"php-cs-fixer/diff": "^1.3",
"symfony/console": "^3.4.17 || ^4.1.6",
"symfony/event-dispatcher": "^3.0 || ^4.0",
"symfony/filesystem": "^3.0 || ^4.0",
"symfony/finder": "^3.0 || ^4.0",
"symfony/options-resolver": "^3.0 || ^4.0",
"symfony/polyfill-php70": "^1.0",
"symfony/polyfill-php72": "^1.4",
"symfony/process": "^3.0 || ^4.0",
"symfony/stopwatch": "^3.0 || ^4.0"
},
"conflict": {
"hhvm": "*"
},
"require-dev": {
"johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0",
"justinrainbow/json-schema": "^5.0",
"keradus/cli-executor": "^1.2",
"mikey179/vfsstream": "^1.6",
"php-coveralls/php-coveralls": "^2.1",
"php-cs-fixer/accessible-object": "^1.0",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.0.1",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.0.1",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1",
"phpunitgoodpractices/traits": "^1.5.1",
"symfony/phpunit-bridge": "^4.0"
},
"suggest": {
"ext-mbstring": "For handling non-UTF8 characters in cache signature.",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.",
"symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
},
"bin": [
"php-cs-fixer"
],
"type": "application",
"extra": {
"branch-alias": {
"dev-master": "2.14-dev"
}
},
"autoload": {
"psr-4": {
"PhpCsFixer\\": "src/"
},
"classmap": [
"tests/Test/AbstractFixerTestCase.php",
"tests/Test/AbstractIntegrationCaseFactory.php",
"tests/Test/AbstractIntegrationTestCase.php",
"tests/Test/Assert/AssertTokensTrait.php",
"tests/Test/IntegrationCase.php",
"tests/Test/IntegrationCaseFactory.php",
"tests/Test/IntegrationCaseFactoryInterface.php",
"tests/Test/InternalIntegrationCaseFactory.php",
"tests/TestCase.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dariusz Rumiński",
"email": "dariusz.ruminski@gmail.com"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "A tool to automatically fix PHP code style",
"time": "2019-01-04T18:29:47+00:00"
},
{ {
"name": "fzaninotto/faker", "name": "fzaninotto/faker",
"version": "v1.8.0", "version": "v1.8.0",
@ -3475,6 +3804,57 @@
"description": "Library for handling version information and constraints", "description": "Library for handling version information and constraints",
"time": "2017-03-05T17:38:23+00:00" "time": "2017-03-05T17:38:23+00:00"
}, },
{
"name": "php-cs-fixer/diff",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/diff.git",
"reference": "78bb099e9c16361126c86ce82ec4405ebab8e756"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/78bb099e9c16361126c86ce82ec4405ebab8e756",
"reference": "78bb099e9c16361126c86ce82ec4405ebab8e756",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7.23 || ^6.4.3",
"symfony/process": "^3.3"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Kore Nordmann",
"email": "mail@kore-nordmann.de"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "SpacePossum"
}
],
"description": "sebastian/diff v2 backport support for PHP5.6",
"homepage": "https://github.com/PHP-CS-Fixer",
"keywords": [
"diff"
],
"time": "2018-02-15T16:58:55+00:00"
},
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
"version": "1.0.1", "version": "1.0.1",
@ -4641,6 +5021,215 @@
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"time": "2016-10-03T07:35:21+00:00" "time": "2016-10-03T07:35:21+00:00"
}, },
{
"name": "symfony/filesystem",
"version": "v4.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "c2ffd9a93f2d6c5be2f68a0aa7953cc229f871f8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/c2ffd9a93f2d6c5be2f68a0aa7953cc229f871f8",
"reference": "c2ffd9a93f2d6c5be2f68a0aa7953cc229f871f8",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2019-01-03T09:07:35+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v4.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "fbcb106aeee72f3450298bf73324d2cc00d083d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/fbcb106aeee72f3450298bf73324d2cc00d083d1",
"reference": "fbcb106aeee72f3450298bf73324d2cc00d083d1",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"time": "2019-01-03T09:07:35+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631",
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"time": "2018-09-21T13:07:52+00:00"
},
{
"name": "symfony/stopwatch",
"version": "v4.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
"reference": "af62b35760fc92c8dbdce659b4eebdfe0e6a0472"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/af62b35760fc92c8dbdce659b4eebdfe0e6a0472",
"reference": "af62b35760fc92c8dbdce659b4eebdfe0e6a0472",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/contracts": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
"time": "2019-01-03T09:07:35+00:00"
},
{ {
"name": "symfony/thanks", "name": "symfony/thanks",
"version": "v1.1.0", "version": "v1.1.0",

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

@ -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 CreateInformationTable extends Migration class CreateInformationTable 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 AddLinkToEjaculations extends Migration class AddLinkToEjaculations 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 CreateTagsTable extends Migration class CreateTagsTable 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 CreateMetadataTable extends Migration class CreateMetadataTable 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 RecreateMetadataTable extends Migration class RecreateMetadataTable 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 ChangeLinkOnEjaculations extends Migration class ChangeLinkOnEjaculations extends Migration
{ {

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
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');
});
}
}

8
dist/bin/tissue-entrypoint.sh vendored Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
if [[ "$APP_DEBUG" == "true" ]]; then
export PHP_INI_SCAN_DIR=":/usr/local/etc/php/php.d"
fi
exec docker-php-entrypoint "$@"

5
dist/php.d/99-xdebug.ini vendored Normal file
View File

@ -0,0 +1,5 @@
; Dockerでのデバッグ用設定
zend_extension=xdebug.so
xdebug.remote_enable=true
xdebug.remote_autostart=true
xdebug.remote_host=host.docker.internal

View File

@ -3,13 +3,8 @@ version: "3"
services: services:
web: web:
build: . build: .
environment: env_file:
DB_CONNECTION: pgsql - .env
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: tissue
DB_USERNAME: tissue
DB_PASSWORD: tissue
volumes: volumes:
- .:/var/www/html - .:/var/www/html
networks: networks:

View File

@ -99,6 +99,10 @@ return [
'attribute-name' => [ 'attribute-name' => [
'rule-name' => 'custom-message', 'rule-name' => 'custom-message',
], ],
'g-recaptcha-response' => [
'required' => '「私はロボットではありません」にチェックを入れてください。',
'captcha' => 'reCAPTCHAチェックに失敗しました。何度試しても解決しない場合、管理者にお問い合わせください。',
],
], ],
/* /*
@ -117,4 +121,4 @@ return [
'password' => 'パスワード', 'password' => 'パスワード',
], ],
]; ];

View File

@ -13,7 +13,7 @@
<div class="form-group"> <div class="form-group">
<label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label> <label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label>
<input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="text" value="{{ old('email') }}" required autofocus> <input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="email" value="{{ old('email') }}" required autofocus>
@if ($errors->has('email')) @if ($errors->has('email'))
<div class="invalid-feedback">{{ $errors->first('email') }}</div> <div class="invalid-feedback">{{ $errors->first('email') }}</div>

View File

@ -16,7 +16,7 @@
<div class="form-group"> <div class="form-group">
<label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label> <label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label>
<input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="text" value="{{ old('email') }}" required autofocus> <input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="email" value="{{ old('email') }}" required autofocus>
@if ($errors->has('email')) @if ($errors->has('email'))
<div class="invalid-feedback">{{ $errors->first('email') }}</div> <div class="invalid-feedback">{{ $errors->first('email') }}</div>

View File

@ -18,7 +18,7 @@
<div class="form-group"> <div class="form-group">
<label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label> <label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label>
<input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="text" value="{{ old('email') }}" required> <input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="email" value="{{ old('email') }}" required>
@if ($errors->has('email')) @if ($errors->has('email'))
<div class="invalid-feedback">{{ $errors->first('email') }}</div> <div class="invalid-feedback">{{ $errors->first('email') }}</div>

View File

@ -2,6 +2,12 @@
@section('title', '新規登録') @section('title', '新規登録')
@push('head')
@if (!empty(config('captcha.secret')))
{!! NoCaptcha::renderJs() !!}
@endif
@endpush
@section('content') @section('content')
<div class="container"> <div class="container">
<h2>新規登録</h2> <h2>新規登録</h2>
@ -21,7 +27,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label> <label for="email"><span class="oi oi-envelope-closed"></span> メールアドレス</label>
<input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="text" value="{{ old('email') }}" required> <input id="email" name="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" type="email" value="{{ old('email') }}" required>
@if ($errors->has('email')) @if ($errors->has('email'))
<div class="invalid-feedback">{{ $errors->first('email') }}</div> <div class="invalid-feedback">{{ $errors->first('email') }}</div>
@ -53,6 +59,16 @@
</div> </div>
</div> </div>
</div> </div>
@if (!empty(config('captcha.secret')))
<div class="form-row ml-1 mt-2 my-4">
<div class="mx-auto">
{!! NoCaptcha::display() !!}
</div>
@if ($errors->has('g-recaptcha-response'))
<div class="invalid-feedback d-block text-center">{{ $errors->first('g-recaptcha-response') }}</div>
@endif
</div>
@endif
<div class="text-center"> <div class="text-center">
<button class="btn btn-primary btn-lg" type="submit">登録</button> <button class="btn btn-primary btn-lg" type="submit">登録</button>

View File

@ -34,7 +34,7 @@
<!-- span --> <!-- span -->
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<h5> <h5>
<a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> &commat;{{ $ejaculation->user->name }}</a> <a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> {{ $ejaculation->user->display_name }}</a>
<a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a> <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
</h5> </h5>
<div> <div>

View File

@ -10,7 +10,7 @@
<!-- span --> <!-- span -->
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<h5> <h5>
<a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> &commat;{{ $ejaculation->user->name }}</a> <a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> {{ $ejaculation->user->display_name }}</a>
<a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a> <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
</h5> </h5>
<div> <div>

View File

@ -26,13 +26,13 @@ Route::get('/checkin/card', function (Request $request, MetadataResolver $resolv
$url = $formatter->normalizeUrl($request->input('url')); $url = $formatter->normalizeUrl($request->input('url'));
$metadata = App\Metadata::find($url); $metadata = App\Metadata::find($url);
if ($metadata == null) { if ($metadata == null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
$resolved = $resolver->resolve($url); $resolved = $resolver->resolve($url);
$metadata = App\Metadata::create([ $metadata = App\Metadata::updateOrCreate(['url' => $url], [
'url' => $url,
'title' => $resolved->title, 'title' => $resolved->title,
'description' => $resolved->description, 'description' => $resolved->description,
'image' => $resolved->image 'image' => $resolved->image,
'expires_at' => $resolved->expires_at
]); ]);
} }
@ -40,5 +40,6 @@ Route::get('/checkin/card', function (Request $request, MetadataResolver $resolv
if (!config('app.debug')) { if (!config('app.debug')) {
$response = $response->setCache(['public' => true, 'max_age' => 86400]); $response = $response->setCache(['public' => true, 'max_age' => 86400]);
} }
return $response; return $response;
}); });

View File

@ -15,7 +15,7 @@ Auth::routes();
Route::get('/', 'HomeController@index')->name('home'); Route::get('/', 'HomeController@index')->name('home');
Route::get('/user', function() { Route::get('/user', function () {
return redirect()->route('user.profile', ['name' => Auth::user()->name]); return redirect()->route('user.profile', ['name' => Auth::user()->name]);
})->middleware('auth')->name('user.profile'); })->middleware('auth')->name('user.profile');
Route::get('/user/{name?}', 'UserController@profile')->name('user.profile'); Route::get('/user/{name?}', 'UserController@profile')->name('user.profile');
@ -36,4 +36,4 @@ Route::get('/info/{id}', 'InfoController@show')->where('id', '[0-9]+')->name('in
Route::redirect('/search', '/search/checkin', 301); Route::redirect('/search', '/search/checkin', 301);
Route::get('/search/checkin', 'SearchController@index')->name('search'); Route::get('/search/checkin', 'SearchController@index')->name('search');
Route::get('/search/related-tag', 'SearchController@relatedTag')->name('search.related-tag'); Route::get('/search/related-tag', 'SearchController@relatedTag')->name('search.related-tag');

View File

@ -2,10 +2,10 @@
namespace Tests\Feature; namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase class ExampleTest extends TestCase
{ {

View File

@ -2,9 +2,9 @@
namespace Tests\Unit; namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class ExampleTest extends TestCase class ExampleTest extends TestCase
{ {