Merge pull request #2147 from pixelfed/staging

Bug fixes
pull/2158/head
daniel 6 years ago committed by GitHub
commit 2617b15ffd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,7 +2,9 @@
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.10.9...dev)
### Added
- ActivityPubFetchService for signed GET requests ([8763bfc5](https://github.com/pixelfed/pixelfed/commit/8763bfc5))
- Custom content warnings for remote posts ([6afc61a4](https://github.com/pixelfed/pixelfed/commit/6afc61a4))
- Thai translations ([https://github.com/pixelfed/pixelfed/commit/74cd536](https://github.com/pixelfed/pixelfed/commit/74cd536))
### Updated
- Updated PostComponent, fix remote urls ([42716ccc](https://github.com/pixelfed/pixelfed/commit/42716ccc))
@ -14,6 +16,17 @@
- Updated PublicApiControllers, fix block/mutes filtering on public timeline ([08383dd4](https://github.com/pixelfed/pixelfed/commit/08383dd4))
- Updated FixUsernames command, fixes remote username search ([0f943f67](https://github.com/pixelfed/pixelfed/commit/0f943f67))
- Updated Timeline component, fix mod tools ([b1d5eb05](https://github.com/pixelfed/pixelfed/commit/b1d5eb05))
- Updated Profile.vue component, fix pagination bug ([46767810](https://github.com/pixelfed/pixelfed/commit/46767810))
- Updated purify config, fix microformats support ([877023fb](https://github.com/pixelfed/pixelfed/commit/877023fb))
- Updated LikeController, fix likes_count bug ([996866cb](https://github.com/pixelfed/pixelfed/commit/996866cb))
- Updated AccountController, added followRequestJson method ([483548e2](https://github.com/pixelfed/pixelfed/commit/483548e2))
- Updated UserInvite model, added sender relation ([591a1929](https://github.com/pixelfed/pixelfed/commit/591a1929))
- Updated migrations, added UIKit ([fcab5010](https://github.com/pixelfed/pixelfed/commit/fcab5010))
- Updated AccountTransformer, added last_fetched_at attribute ([38b0233e](https://github.com/pixelfed/pixelfed/commit/38b0233e))
- Updated StoryItemTransformer, increase story length to 5 seconds ([924e424c](https://github.com/pixelfed/pixelfed/commit/924e424c))
- Updated StatusController, fix reblog_count bug ([1dc65e93](https://github.com/pixelfed/pixelfed/commit/1dc65e93))
- Updated NotificationCard.vue component, add follow requests at top of card, remove card-header ([5e48ffca](https://github.com/pixelfed/pixelfed/commit/5e48ffca))
- Updated RemoteProfile.vue component, add warning for empty profiles and last_fetched_at ([66f44a9d](https://github.com/pixelfed/pixelfed/commit/66f44a9d))
## [v0.10.9 (2020-04-17)](https://github.com/pixelfed/pixelfed/compare/v0.10.8...v0.10.9)

@ -327,6 +327,27 @@ class AccountController extends Controller
return view('account.follow-requests', compact('followers'));
}
public function followRequestsJson(Request $request)
{
$pid = Auth::user()->profile_id;
$followers = FollowRequest::whereFollowingId($pid)->orderBy('id','desc')->whereIsRejected(0)->get();
$res = [
'count' => $followers->count(),
'accounts' => $followers->take(10)->map(function($a) {
$actor = $a->actor;
return [
'id' => $actor->id,
'username' => $actor->username,
'avatar' => $actor->avatarUrl(),
'url' => $actor->url(),
'local' => $actor->domain == null,
'following' => $actor->followedBy(Auth::user()->profile)
];
})
];
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function followRequestHandle(Request $request)
{
$this->validate($request, [

@ -27,7 +27,7 @@ class LikeController extends Controller
$profile = $user->profile;
$status = Status::findOrFail($request->input('item'));
$count = $status->likes_count;
$count = $status->likes()->count();
if ($status->likes()->whereProfileId($profile->id)->count() !== 0) {
$like = Like::whereProfileId($profile->id)->whereStatusId($status->id)->firstOrFail();

@ -175,7 +175,7 @@ class StatusController extends Controller
->whereIn('scope', ['public', 'unlisted'])
->findOrFail($request->input('item'));
$count = $status->shares_count;
$count = $status->shares()->count();
$exists = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)

@ -0,0 +1,10 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UIKitController extends Controller
{
//
}

@ -8,6 +8,8 @@ class ModLog extends Model
{
protected $visible = ['id'];
protected $fillable = ['*'];
public function admin()
{
return $this->belongsTo(User::class, 'user_id');

@ -18,7 +18,10 @@ class Profile extends Model
*/
public $incrementing = false;
protected $dates = ['deleted_at'];
protected $dates = [
'deleted_at',
'last_fetched_at'
];
protected $hidden = ['private_key'];
protected $visible = ['id', 'user_id', 'username', 'name'];
protected $fillable = ['user_id'];

@ -0,0 +1,59 @@
<?php
namespace App\Services;
use Zttp\Zttp;
use App\Profile;
use App\Util\ActivityPub\Helpers;
use App\Util\ActivityPub\HttpSignature;
class ActivityPubFetchService
{
public $signed = true;
public $actor;
public $url;
public $headers = [
'Accept' => 'application/activity+json, application/json',
'User-Agent' => 'PixelfedBot - https://pixelfed.org'
];
public static function queue()
{
return new self;
}
public function signed($signed = true)
{
$this->signed = $signed;
return $this;
}
public function actor($profile)
{
$this->actor = $profile;
return $this;
}
public function url($url)
{
if(!Helpers::validateUrl($url)) {
throw new \Exception('Invalid URL');
}
$this->url = $url;
return $this;
}
public function get()
{
if($this->signed == true && $this->actor == null) {
throw new \Exception('Cannot sign request without actor');
}
return $this->signedRequest();
}
protected function signedRequest()
{
$this->headers = HttpSignature::sign($this->actor, $this->url, false, $this->headers);
return Zttp::withHeaders($this->headers)->get($this->url)->body();
}
}

@ -34,7 +34,8 @@ class AccountTransformer extends Fractal\TransformerAbstract
'local' => (bool) $local,
'is_admin' => (bool) $is_admin,
'created_at' => $profile->created_at->toJSON(),
'header_bg' => $profile->header_bg
'header_bg' => $profile->header_bg,
'last_fetched_at' => optional($profile->last_fetched_at)->toJSON()
];
}

@ -14,7 +14,7 @@ class StoryItemTransformer extends Fractal\TransformerAbstract
return [
'id' => (string) $item->id,
'type' => $item->type,
'length' => $item->duration != 0 ? $item->duration : 3,
'length' => 5,
'src' => $item->url(),
'preview' => null,
'link' => null,

@ -0,0 +1,21 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class UIKit extends Model
{
protected $table = 'uikit';
protected $fillable = [
'k',
'v',
'defv',
'dhis'
];
public static function section($k)
{
return (new self)->where('k', $k)->first()->v;
}
}

@ -6,10 +6,13 @@ use Illuminate\Database\Eloquent\Model;
class UserInvite extends Model
{
public function sender()
{
return $this->belongsTo(Profile::class, 'profile_id');
}
public function url()
{
$path = '/i/invite/code';
$url = url($path, [$this->key, $this->token]);
return $url;
return url("/i/invite/code/{$this->key}/{$this->token}");
}
}

@ -68,8 +68,8 @@ return [
*/
'HTML.Allowed' => env('RESTRICT_HTML_TYPES', true) ?
'a[href|title|rel],p,span,br' :
'a[href|title|rel],p,span,strong,em,del,b,i,s,strike,h1,h2,h3,h4,h5,h6,ul,ol,li,br',
'a[href|title|rel|class],p[class],span[class],br' :
'a[href|title|rel|class],p[class],span[class],strong,em,del,b,i,s,strike,h1,h2,h3,h4,h5,h6,ul,ol,li,br',
/*
@ -133,6 +133,27 @@ return [
'AutoFormat.RemoveEmpty' => false,
'Attr.AllowedClasses' => [
'h-feed',
'h-entry',
'h-cite',
'h-card',
'p-author',
'p-name',
'p-in-reply-to',
'p-repost-of',
'p-comment',
'u-photo',
'u-uid',
'u-url',
'dt-published',
'e-content',
'mention',
'hashtag',
'ellipsis',
'invisible'
],
'Attr.AllowedRel' => [
'noreferrer',
'noopener',

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUikitTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('uikit', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('k')->unique()->index();
$table->text('v')->nullable();
$table->json('meta')->nullable();
// default value for rollbacks
$table->text('defv')->nullable();
// delta history
$table->text('dhis')->nullable();
$table->unsignedInteger('edit_count')->default(0)->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('uikit');
}
}

2
public/js/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -3,7 +3,7 @@
"/js/vendor.js": "/js/vendor.js?id=983240a74cc998d87b92",
"/js/ace.js": "/js/ace.js?id=a575b37c2085b5003666",
"/js/activity.js": "/js/activity.js?id=028cbbe598f925bb3414",
"/js/app.js": "/js/app.js?id=360dc653e947aa970981",
"/js/app.js": "/js/app.js?id=36bcca155ecd9591085b",
"/css/app.css": "/css/app.css?id=7c5f75a2d1869434a6e5",
"/css/appdark.css": "/css/appdark.css?id=851d7357ef5b915c16cc",
"/css/landing.css": "/css/landing.css?id=c32626242434e958d457",
@ -18,14 +18,14 @@
"/js/hashtag.js": "/js/hashtag.js?id=e6b41cab117cb03c7d2a",
"/js/loops.js": "/js/loops.js?id=ac610897b12207c829b9",
"/js/mode-dot.js": "/js/mode-dot.js?id=1225a9aac7a93d5d232f",
"/js/profile.js": "/js/profile.js?id=21d25df460d1fa9bab60",
"/js/profile.js": "/js/profile.js?id=0c257ca93d37f7049680",
"/js/profile-directory.js": "/js/profile-directory.js?id=7160b00d9beda164f1bc",
"/js/quill.js": "/js/quill.js?id=9b15ab0ae830e7293390",
"/js/rempos.js": "/js/rempos.js?id=05c5bbe056fec540d28a",
"/js/rempro.js": "/js/rempro.js?id=1cef29f9c7b39704a86a",
"/js/rempro.js": "/js/rempro.js?id=750317b23c9c1b3b7ede",
"/js/search.js": "/js/search.js?id=2d76d7d28de3b4691bc7",
"/js/status.js": "/js/status.js?id=05b227c197bc00d64851",
"/js/status.js": "/js/status.js?id=19efdc555a9b04b59775",
"/js/story-compose.js": "/js/story-compose.js?id=86751d072969424c6e30",
"/js/theme-monokai.js": "/js/theme-monokai.js?id=3b6e62701f12b717cc5c",
"/js/timeline.js": "/js/timeline.js?id=9f28f3e95c643763c4bf"
"/js/timeline.js": "/js/timeline.js?id=b72294f7bb8daa02e306"
}

@ -69,6 +69,31 @@ window.App.util = {
return 0;
}
return new Intl.NumberFormat(locale, { notation: notation , compactDisplay: "short" }).format(count);
}),
timeAgo: (function(ts) {
let date = Date.parse(ts);
let seconds = Math.floor((new Date() - date) / 1000);
let interval = Math.floor(seconds / 31536000);
if (interval >= 1) {
return interval + "y";
}
interval = Math.floor(seconds / 604800);
if (interval >= 1) {
return interval + "w";
}
interval = Math.floor(seconds / 86400);
if (interval >= 1) {
return interval + "d";
}
interval = Math.floor(seconds / 3600);
if (interval >= 1) {
return interval + "h";
}
interval = Math.floor(seconds / 60);
if (interval >= 1) {
return interval + "m";
}
return Math.floor(seconds) + "s";
})
},
filters: [

@ -2,19 +2,19 @@
<div>
<transition name="fade">
<div class="card notification-card shadow-none border">
<div class="card-header bg-white">
<p class="mb-0 d-flex align-items-center justify-content-between">
<span data-toggle="tooltip" data-placement="bottom"><i class="fas fa-redo fa-lg text-white"></i></span>
<span class="small text-dark text-uppercase font-weight-bold">Alerts</span>
<a class="text-decoration-none text-muted" href="/account/activity"><i class="fas fa-inbox fa-lg"></i></a>
</p>
</div>
<div class="card-body loader text-center" style="height: 200px;">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div class="card-body pt-2 px-0 py-0 contents" style="max-height: 200px; overflow-y: scroll;">
<div v-if="notifications.length > 0" class="card-body px-0 py-0 contents" style="max-height: 240px; overflow-y: scroll;">
<div v-if="profile.locked" class="media align-items-center mt-n2 px-3 py-2 border-bottom border-lighter bg-light cursor-pointer" @click="redirect('/account/follow-requests')">
<div class="media-body font-weight-light pt-2 small d-flex align-items-center justify-content-between">
<p class="mb-0 text-lighter"><i class="fas fa-cog text-light"></i></p>
<p class="text-center pt-1 mb-1 text-dark font-weight-bold"><strong>{{followRequests.count}}</strong> Follow Requests</p>
<p class="mb-0 text-lighter"><i class="fas fa-chevron-right"></i></p>
</div>
</div>
<div v-if="notifications.length > 0" class="media align-items-center px-3 py-2 border-bottom border-light" v-for="(n, index) in notifications">
<img class="mr-2 rounded-circle" style="border:1px solid #ccc" :src="n.account.avatar" alt="" width="32px" height="32px" onerror="this.onerror=null;this.src='/storage/avatars/default.png';">
<div class="media-body font-weight-light small">
@ -76,11 +76,20 @@
notifications: {},
notificationCursor: 2,
notificationMaxId: 0,
profile: {
locked: false
},
followRequests: null
};
},
mounted() {
let self = this;
this.fetchNotifications();
setTimeout(function() {
self.profile = window._sharedData.curUser;
self.fetchFollowRequests();
}, 500);
},
updated() {
@ -138,29 +147,7 @@
},
timeAgo(ts) {
let date = Date.parse(ts);
let seconds = Math.floor((new Date() - date) / 1000);
let interval = Math.floor(seconds / 31536000);
if (interval >= 1) {
return interval + "y";
}
interval = Math.floor(seconds / 604800);
if (interval >= 1) {
return interval + "w";
}
interval = Math.floor(seconds / 86400);
if (interval >= 1) {
return interval + "d";
}
interval = Math.floor(seconds / 3600);
if (interval >= 1) {
return interval + "h";
}
interval = Math.floor(seconds / 60);
if (interval >= 1) {
return interval + "m";
}
return Math.floor(seconds) + "s";
return window.App.util.format.timeAgo(ts);
},
mentionUrl(status) {
@ -219,6 +206,19 @@
}
}
});
},
fetchFollowRequests() {
if(window._sharedData.curUser.locked == true) {
axios.get('/account/follow-requests.json')
.then(res => {
this.followRequests = res.data;
})
}
},
redirect(url) {
window.location.href = url;
}
}
}

@ -1066,29 +1066,7 @@ export default {
},
timeAgo(ts) {
let date = Date.parse(ts);
let seconds = Math.floor((new Date() - date) / 1000);
let interval = Math.floor(seconds / 31536000);
if (interval >= 1) {
return interval + "y";
}
interval = Math.floor(seconds / 604800);
if (interval >= 1) {
return interval + "w";
}
interval = Math.floor(seconds / 86400);
if (interval >= 1) {
return interval + "d";
}
interval = Math.floor(seconds / 3600);
if (interval >= 1) {
return interval + "h";
}
interval = Math.floor(seconds / 60);
if (interval >= 1) {
return interval + "m";
}
return Math.floor(seconds) + "s";
return App.util.format.timeAgo(ts);
},
emojiReaction() {

@ -760,8 +760,13 @@
self.ids.push(d.id);
}
});
let max = Math.min(...this.ids);
if(max == this.max_id) {
$state.complete();
return;
}
this.min_id = Math.max(...this.ids);
this.max_id = Math.min(...this.ids);
this.max_id = max;
$state.loaded();
this.loading = false;
} else {

@ -33,8 +33,7 @@
</span>
</div>
<p class="pl-2 h4 font-weight-bold mb-1">{{profile.display_name}}</p>
<p class="pl-2 font-weight-bold mb-1 text-muted">{{profile.acct}}</p>
<p class="pl-2 text-muted small pt-3" v-html="profile.note"></p>
<p class="pl-2 font-weight-bold mb-2 text-muted">{{profile.acct}}</p>
<p class="pl-2 text-muted small d-flex justify-content-between">
<span>
<span class="font-weight-bold text-dark">{{profile.statuses_count}}</span>
@ -49,8 +48,10 @@
<span>Followers</span>
</span>
</p>
<p class="pl-2 text-muted small pt-2" v-html="profile.note"></p>
</div>
</div>
<p class="small text-lighter p-2">Last updated: <time :datetime="profile.last_fetched_at">{{timeAgo(profile.last_fetched_at, 'ago')}}</time></p>
</div>
<div class="col-12 col-md-8 pt-5">
<div class="row">
@ -110,9 +111,18 @@
</div>
</div>
<!-- <div class="col-12 mt-4">
<div v-if="feed.length == 0" class="col-12 mb-2">
<div class="d-flex justify-content-center align-items-center bg-white border rounded" style="height:60vh;">
<div class="text-center">
<p class="mb-0 lead">No posts found.</p>
<p class="">We haven't seen any posts from this account.</p>
</div>
</div>
</div>
<div v-else class="col-12 mt-4">
<p class="text-center mb-0 px-0"><button class="btn btn-outline-primary btn-block font-weight-bold">Load More</button></p>
</div> -->
</div>
</div>
</div>
</div>
@ -191,6 +201,8 @@
warning: false,
ctxMenuStatus: false,
ctxMenuRelationship: false,
fetchingRemotePosts: false,
showMutualFollowers: false
}
},
@ -451,6 +463,24 @@
swal('Error', 'Something went wrong. Please try again later.', 'error');
});
},
manuallyFetchRemotePosts($event) {
this.fetchingRemotePosts = true;
event.target.blur();
swal(
'Fetching Remote Posts',
'Check back in a few minutes!',
'info'
);
},
timeAgo(ts, suffix = false) {
if(ts == null) {
return 'never';
}
suffix = suffix ? ' ' + suffix : '';
return App.util.format.timeAgo(ts) + suffix;
},
}
}
</script>

@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'ข้อมูลไม่ตรงกับบันทึกของเรา',
'throttle' => 'ลงชื่อเข้าหลายครั้งเกินไป โปรดลองอีกครั้งภายใน :seconds วินาที',
];

@ -0,0 +1,11 @@
<?php
return [
'compose' => [
'invalid' => [
'album' => 'ต้องมีอย่างรูปหรือวีดิโอเป็นอย่างน้อย',
],
],
];

@ -0,0 +1,26 @@
<?php
return [
'helpcenter' => 'Help Center',
'whatsnew' => 'What\'s New',
'gettingStarted' => 'Getting Started',
'sharingMedia' => 'Sharing Media',
'profile' => 'Profile',
'stories' => 'Stories',
'hashtags' => 'Hashtags',
'discover' => 'Discover',
'directMessages' => 'Direct Messages',
'timelines' => 'Timelines',
'embed' => 'Embed',
'communityGuidelines' => 'Community Guidelines',
'whatIsTheFediverse' => 'What is the fediverse?',
'controllingVisibility' => 'Controlling Visibility',
'blockingAccounts' => 'Blocking Accounts',
'safetyTips' => 'Safety Tips',
'reportSomething' => 'Report Something',
'dataPolicy' => 'Data Policy'
];

@ -0,0 +1,19 @@
<?php
return [
'search' => 'ค้นหา',
'home' => 'หน้าหลัก',
'local' => 'Local',
'network' => 'Network',
'discover' => 'Discover',
'viewMyProfile' => 'ดูโพรไฟล์',
'myProfile' => 'โพรไฟล์ของฉัน',
'myTimeline' => 'ทามไลน์ของฉัน',
'publicTimeline' => 'ทามไลน์สาธารณะ',
'remoteFollow' => 'Remote Follow',
'settings' => 'ตั้งค่า',
'admin' => 'ผู้ดูแล',
'logout' => 'ออกจากระบบ',
'directMessages' => 'ส่งข้อความ',
'composePost' => 'สร้างโพสต์',
];

@ -0,0 +1,12 @@
<?php
return [
'likedPhoto' => 'ถูกใจโพสต์ของคุณ',
'likedComment' => 'ถูกใจความเห็นของคุณ',
'startedFollowingYou' => 'ได้ติดตามคุณแล้ว',
'commented' => 'ได้แสดงความเห็นโพสต์ของคุณ',
'mentionedYou' => 'พูดถึงคุณ',
'shared' => 'แชร์โพสต์ของคุณ',
];

@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '« ก่อนหน้า',
'next' => 'ถัดไป »',
];

@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'password' => 'รหัสผ่านจำเป็นต้องมีอย่างน้อยหกตัวอักษร',
'reset' => 'คุณได้เปลี่ยนรหัสผ่านเรียบร้อยแล้ว!',
'sent' => 'หากอีเมลของคุณอยู่ในฐานข้อมูลของเราแล้ว ในอีกไม่กี่นาทีคุณจะได้รับอีเมลเพื่อแก้ใขรหัสผ่าน หากไม่พบอีเมล โปรดไปตรวจดูที่ถังขยะ',
'token' => 'ใช้รหัสผ่านนี้ไม่ได้',
'user' => 'หากอีเมลของคุณอยู่ในฐานข้อมูลของเราแล้ว ในอีกไม่กี่นาทีคุณจะได้รับอีเมลเพื่อแก้ใขรหัสผ่าน หากไม่พบอีเมล โปรดไปตรวจดูที่ถังขยะ',
];

@ -0,0 +1,15 @@
<?php
return [
'emptyTimeline' => 'ผู้ใช้นี้ยังไม่มีโพสต์อะไร!',
'emptyFollowers' => 'ผู้ใช้นี้ยังไม่มีผู้ติดตาม!',
'emptyFollowing' => 'ผู้ใช้นี้ยังไม่ได้ติดตามใครเลย!',
'emptySaved' => 'คุณยังไม่ได้บันทึกโพสต์ใด ๆ!',
'savedWarning' => 'คุณเท่านั้นที่สามารถดูโพสต์นี้ได้',
'privateProfileWarning' => 'บัญชีนี้เป็นบัญชีส่วนบุคคล',
'alreadyFollow' => ':username ได้ติดตาม',
'loginToSeeProfile' => 'ดูรูปและวีดิโอ',
'status.disabled.header' => 'บัญชีไม่สามารถใช้งานได้',
'status.disabled.body' => 'เสียใจด้วยนะ บัญชีนี้ไม่สามารถใช้งานได้ โปรดลองใหม่อีกครั้ง',
];

@ -0,0 +1,20 @@
<?php
return [
'about' => 'เกี่ยวกับ',
'help' => 'ช่วยเหลือ',
'language' => 'ภาษา',
'fediverse' => 'Fediverse',
'opensource' => 'Open Source',
'terms' => 'ข้อกำหนด',
'privacy' => 'ความเป็นส่วนตัว',
'l10nWip' => 'เรากำลังอยู่ดำเนินการแปลเป็นภาษาของคุณ',
'currentLocale' => 'สถานที่ปัจจุบัน',
'selectLocale' => 'เลือกภาษาที่ได้รับการสนับสนุน',
'contact' => 'ติดต่อ',
'contact-us' => 'ติดต่อเรา',
'places' => 'สถานที่',
'profiles' => 'โพรไฟล์',
];

@ -0,0 +1,7 @@
<?php
return [
'emptyPersonalTimeline' => 'ทามไลน์ของคุณยังไม่มีอะไร!',
];

@ -0,0 +1,122 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute must be accepted.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute may only contain letters.',
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
'alpha_num' => 'The :attribute may only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'date' => 'The :attribute is not a valid date.',
'date_format' => 'The :attribute does not match the format :format.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'email' => 'The :attribute must be a valid email address.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'max' => [
'numeric' => 'The :attribute may not be greater than :max.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'string' => 'The :attribute may not be greater than :max characters.',
'array' => 'The :attribute may not have more than :max items.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values is present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid zone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute format is invalid.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => [],
];

@ -272,6 +272,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('activity', 'AccountController@notifications')->name('notifications');
Route::get('follow-requests', 'AccountController@followRequests')->name('follow-requests');
Route::post('follow-requests', 'AccountController@followRequestHandle');
Route::get('follow-requests.json', 'AccountController@followRequestsJson');
});
Route::group(['prefix' => 'settings'], function () {

Loading…
Cancel
Save