Normalize EOL style + newline at end of files.

This commit is contained in:
Kira 2020-10-24 05:47:20 -07:00
parent 77328c75a8
commit db8d4c4773
100 changed files with 2338 additions and 2335 deletions

View File

@ -1,13 +1,13 @@
module Admin
class ExceptionsController < ApplicationController
before_action :admin_only
def index
@exception_logs = ExceptionLog.order(id: :desc).paginate(params[:page], limit: 100)
end
def show
@exception_log = ExceptionLog.find(params[:id])
end
end
end
module Admin
class ExceptionsController < ApplicationController
before_action :admin_only
def index
@exception_logs = ExceptionLog.order(id: :desc).paginate(params[:page], limit: 100)
end
def show
@exception_log = ExceptionLog.find(params[:id])
end
end
end

View File

@ -1,116 +1,116 @@
class BlipsController < ApplicationController
class BlipTooOld < Exception ; end
respond_to :html, :json
before_action :member_only, only: [:create, :new, :update, :edit, :hide]
before_action :moderator_only, only: [:unhide, :destroy]
rescue_from BlipTooOld, with: :blip_too_old
def index
@blips = Blip.visible.search(search_params).paginate(params[:page], limit: params[:limit])
respond_with(@blips)
end
def show
@blip = Blip.find(params[:id])
check_privilege(@blip)
@parent = @blip.response_to
@children = Blip.visible.where('response_to = ?', @blip.id).paginate(params[:page])
respond_with(@blip)
end
def edit
@blip = Blip.find(params[:id])
check_edit_privilege(@blip)
respond_with(@blip)
end
def update
@blip = Blip.find(params[:id])
check_edit_privilege(@blip)
Blip.transaction do
@blip.update(blip_params(:update))
ModAction.log(:blip_update, {blip_id: @blip.id, user_id: @blip.creator_id})
end
flash[:notice] = 'Blip updated'
respond_with(@blip)
end
def hide
@blip = Blip.find(params[:id])
check_hide_privilege(@blip)
Blip.transaction do
@blip.update(is_hidden: true)
ModAction.log(:blip_hide, {blip_id: @blip.id, user_id: @blip.creator_id})
end
respond_with(@blip)
end
def unhide
@blip = Blip.find(params[:id])
Blip.transaction do
@blip.update(is_hidden: false)
ModAction.log(:blip_unhide, {blip_id: @blip.id, user_id: @blip.creator_id})
end
respond_with(@blip)
end
def destroy
@blip = Blip.find(params[:id])
ModAction.log(:blip_delete, {blip_id: @blip.id, user_id: @blip.creator_id})
@blip.destroy
flash[:notice] = 'Blip deleted'
respond_with(@blip) do |format|
format.html do
redirect_back(fallback_location: blip_path(id: @blip.response_to))
end
end
end
def new
@blip = Blip.new
end
def create
@blip = Blip.create(blip_params(:create))
flash[:notice] = @blip.valid? ? "Blip posted" : @blip.errors.full_messages.join("; ")
respond_with(@blip) do |format|
format.html do
redirect_back(fallback_location: blips_path)
end
end
end
private
def search_params
params.fetch(:search, {}).permit!
end
def blip_params(mode)
allowed = [:body]
allowed << :response_to if mode == :create
params.require(:blip).permit(allowed)
end
def blip_too_old
redirect_back(fallback_location: blips_path, flash: {notice: 'You cannot edit blips more than 5 minutes old'})
end
def check_privilege(blip)
raise User::PrivilegeError unless blip.visible_to?(CurrentUser.user)
end
def check_hide_privilege(blip)
raise User::PrivilegeError unless blip.can_hide?(CurrentUser.user)
end
def check_edit_privilege(blip)
return if CurrentUser.is_moderator?
raise User::PrivilegeError if blip.creator_id != CurrentUser.id
raise BlipTooOld if blip.created_at < 5.minutes.ago
end
end
class BlipsController < ApplicationController
class BlipTooOld < Exception ; end
respond_to :html, :json
before_action :member_only, only: [:create, :new, :update, :edit, :hide]
before_action :moderator_only, only: [:unhide, :destroy]
rescue_from BlipTooOld, with: :blip_too_old
def index
@blips = Blip.visible.search(search_params).paginate(params[:page], limit: params[:limit])
respond_with(@blips)
end
def show
@blip = Blip.find(params[:id])
check_privilege(@blip)
@parent = @blip.response_to
@children = Blip.visible.where('response_to = ?', @blip.id).paginate(params[:page])
respond_with(@blip)
end
def edit
@blip = Blip.find(params[:id])
check_edit_privilege(@blip)
respond_with(@blip)
end
def update
@blip = Blip.find(params[:id])
check_edit_privilege(@blip)
Blip.transaction do
@blip.update(blip_params(:update))
ModAction.log(:blip_update, {blip_id: @blip.id, user_id: @blip.creator_id})
end
flash[:notice] = 'Blip updated'
respond_with(@blip)
end
def hide
@blip = Blip.find(params[:id])
check_hide_privilege(@blip)
Blip.transaction do
@blip.update(is_hidden: true)
ModAction.log(:blip_hide, {blip_id: @blip.id, user_id: @blip.creator_id})
end
respond_with(@blip)
end
def unhide
@blip = Blip.find(params[:id])
Blip.transaction do
@blip.update(is_hidden: false)
ModAction.log(:blip_unhide, {blip_id: @blip.id, user_id: @blip.creator_id})
end
respond_with(@blip)
end
def destroy
@blip = Blip.find(params[:id])
ModAction.log(:blip_delete, {blip_id: @blip.id, user_id: @blip.creator_id})
@blip.destroy
flash[:notice] = 'Blip deleted'
respond_with(@blip) do |format|
format.html do
redirect_back(fallback_location: blip_path(id: @blip.response_to))
end
end
end
def new
@blip = Blip.new
end
def create
@blip = Blip.create(blip_params(:create))
flash[:notice] = @blip.valid? ? "Blip posted" : @blip.errors.full_messages.join("; ")
respond_with(@blip) do |format|
format.html do
redirect_back(fallback_location: blips_path)
end
end
end
private
def search_params
params.fetch(:search, {}).permit!
end
def blip_params(mode)
allowed = [:body]
allowed << :response_to if mode == :create
params.require(:blip).permit(allowed)
end
def blip_too_old
redirect_back(fallback_location: blips_path, flash: {notice: 'You cannot edit blips more than 5 minutes old'})
end
def check_privilege(blip)
raise User::PrivilegeError unless blip.visible_to?(CurrentUser.user)
end
def check_hide_privilege(blip)
raise User::PrivilegeError unless blip.can_hide?(CurrentUser.user)
end
def check_edit_privilege(blip)
return if CurrentUser.is_moderator?
raise User::PrivilegeError if blip.creator_id != CurrentUser.id
raise BlipTooOld if blip.created_at < 5.minutes.ago
end
end

View File

@ -1,14 +1,14 @@
class EditHistoriesController < ApplicationController
respond_to :html
before_action :moderator_only
def index
@edit_history = EditHistory.includes(:user).paginate(params[:page], limit: params[:limit])
respond_with(@edit_history)
end
def show
@edits = EditHistoryDecorator.decorate_collection(EditHistory.includes(:user).where('versionable_id = ? AND versionable_type = ?', params[:id], params[:type]).order(:id))
respond_with(@edits)
end
end
class EditHistoriesController < ApplicationController
respond_to :html
before_action :moderator_only
def index
@edit_history = EditHistory.includes(:user).paginate(params[:page], limit: params[:limit])
respond_with(@edit_history)
end
def show
@edits = EditHistoryDecorator.decorate_collection(EditHistory.includes(:user).where('versionable_id = ? AND versionable_type = ?', params[:id], params[:type]).order(:id))
respond_with(@edits)
end
end

View File

@ -1,45 +1,45 @@
class EmailsController < ApplicationController
respond_to :html
def resend_confirmation
if IpBan.is_banned? CurrentUser.ip_addr
redirect_to home_users_path, notice: "An error occurred trying to send an activation email"
return
end
raise User::PrivilegeError.new("Must be logged in to resend verification email.") if CurrentUser.is_anonymous?
raise User::PrivilegeError.new("Account already active.") if CurrentUser.is_verified?
raise User::PrivilegeError.new('Cannot send confirmation because the email is not allowed.') if EmailBlacklist.is_banned?(CurrentUser.user.email)
if RateLimiter.check_limit("emailconfirm:#{CurrentUser.id}", 1, 12.hours)
raise User::PrivilegeError.new("Confirmation email sent too recently. Please wait at least 12 hours between sends.")
end
RateLimiter.hit("emailconfirm:#{CurrentUser.id}", 12.hours)
Maintenance::User::EmailConfirmationMailer.confirmation(CurrentUser.user).deliver_now
redirect_to home_users_path, notice: "Activation email resent"
end
def activate_user
if IpBan.is_banned? CurrentUser.ip_addr
redirect_to home_users_path, notice: 'An error occurred trying to activate your account'
return
end
user = verify_get_user(:activate)
raise User::PrivilegeError.new('Account cannot be activated because the email is not allowed.') if EmailBlacklist.is_banned?(user.email)
raise User::PrivilegeError.new('Account already activated.') if user.is_verified?
user.mark_verified!
redirect_to home_users_path, notice: "Account activated"
end
private
def verify_get_user(purpose)
message = EmailLinkValidator.validate(params[:sig], purpose)
raise User::PrivilegeError.new("Invalid activation link.") if message.blank? || !message
User.find(message.to_i)
end
end
class EmailsController < ApplicationController
respond_to :html
def resend_confirmation
if IpBan.is_banned? CurrentUser.ip_addr
redirect_to home_users_path, notice: "An error occurred trying to send an activation email"
return
end
raise User::PrivilegeError.new("Must be logged in to resend verification email.") if CurrentUser.is_anonymous?
raise User::PrivilegeError.new("Account already active.") if CurrentUser.is_verified?
raise User::PrivilegeError.new('Cannot send confirmation because the email is not allowed.') if EmailBlacklist.is_banned?(CurrentUser.user.email)
if RateLimiter.check_limit("emailconfirm:#{CurrentUser.id}", 1, 12.hours)
raise User::PrivilegeError.new("Confirmation email sent too recently. Please wait at least 12 hours between sends.")
end
RateLimiter.hit("emailconfirm:#{CurrentUser.id}", 12.hours)
Maintenance::User::EmailConfirmationMailer.confirmation(CurrentUser.user).deliver_now
redirect_to home_users_path, notice: "Activation email resent"
end
def activate_user
if IpBan.is_banned? CurrentUser.ip_addr
redirect_to home_users_path, notice: 'An error occurred trying to activate your account'
return
end
user = verify_get_user(:activate)
raise User::PrivilegeError.new('Account cannot be activated because the email is not allowed.') if EmailBlacklist.is_banned?(user.email)
raise User::PrivilegeError.new('Account already activated.') if user.is_verified?
user.mark_verified!
redirect_to home_users_path, notice: "Account activated"
end
private
def verify_get_user(purpose)
message = EmailLinkValidator.validate(params[:sig], purpose)
raise User::PrivilegeError.new("Invalid activation link.") if message.blank? || !message
User.find(message.to_i)
end
end

View File

@ -1,52 +1,52 @@
class PostReportReasonsController < ApplicationController
respond_to :html
before_action :admin_only
def index
@reasons = PostReportReason.order('id DESC')
respond_with(@reasons)
end
def new
@reason = PostReportReason.new
end
def destroy
@reason = PostReportReason.find(params[:id])
PostReportReason.transaction do
@reason.destroy
ModAction.log(:report_reason_delete, {reason: @reason.reason, user_id: @reason.creator_id})
end
respond_with(@reason)
end
def create
PostReportReason.transaction do
@reason = PostReportReason.create(reason_params)
ModAction.log(:report_reason_create, {reason: @reason.reason})
end
flash[:notice] = @reason.valid? ? "Post report reason created" : @reason.errors.full_messages.join("; ")
redirect_to post_report_reasons_path
end
def edit
@reason = PostReportReason.find(params[:id])
end
def update
@reason = PostReportReason.find(params[:id])
PostReportReason.transaction do
@reason.update(reason_params)
ModAction.log(:report_reason_update, {reason: @reason.reason, reason_was: @reason.reason_before_last_save}) if @reason.valid?
end
flash[:notice] = @reason.valid? ? 'Post report reason updated' : @reason.errors.full_messages.join('; ')
redirect_to post_report_reasons_path
end
private
def reason_params
params.require(:post_report_reason).permit(%i[reason description])
end
end
class PostReportReasonsController < ApplicationController
respond_to :html
before_action :admin_only
def index
@reasons = PostReportReason.order('id DESC')
respond_with(@reasons)
end
def new
@reason = PostReportReason.new
end
def destroy
@reason = PostReportReason.find(params[:id])
PostReportReason.transaction do
@reason.destroy
ModAction.log(:report_reason_delete, {reason: @reason.reason, user_id: @reason.creator_id})
end
respond_with(@reason)
end
def create
PostReportReason.transaction do
@reason = PostReportReason.create(reason_params)
ModAction.log(:report_reason_create, {reason: @reason.reason})
end
flash[:notice] = @reason.valid? ? "Post report reason created" : @reason.errors.full_messages.join("; ")
redirect_to post_report_reasons_path
end
def edit
@reason = PostReportReason.find(params[:id])
end
def update
@reason = PostReportReason.find(params[:id])
PostReportReason.transaction do
@reason.update(reason_params)
ModAction.log(:report_reason_update, {reason: @reason.reason, reason_was: @reason.reason_before_last_save}) if @reason.valid?
end
flash[:notice] = @reason.valid? ? 'Post report reason updated' : @reason.errors.full_messages.join('; ')
redirect_to post_report_reasons_path
end
private
def reason_params
params.require(:post_report_reason).permit(%i[reason description])
end
end

View File

@ -1,9 +1,9 @@
class TagTypeVersionsController < ApplicationController
respond_to :html, :jso
def index
@tag_versions = TagTypeVersion.search(params[:search]).paginate(params[:page], limit: params[:limit])
respond_with(@tag_versions)
end
end
class TagTypeVersionsController < ApplicationController
respond_to :html, :jso
def index
@tag_versions = TagTypeVersion.search(params[:search]).paginate(params[:page], limit: params[:limit])
respond_with(@tag_versions)
end
end

View File

@ -1,3 +1,3 @@
class PaginatedDecorator < Draper::CollectionDecorator
delegate :current_page, :total_pages, :is_first_page?, :is_last_page?, :sequential_paginator_mode, :records, :total_count
end
class PaginatedDecorator < Draper::CollectionDecorator
delegate :current_page, :total_pages, :is_first_page?, :is_last_page?, :sequential_paginator_mode, :records, :total_count
end

View File

@ -1,12 +1,12 @@
module TicketHelper
def pretty_ticket_status(ticket)
status = ticket.status
if status == "partial"
"Under Investigation"
elsif status == "approved"
"Investigated"
else
status.titleize
end
end
end
module TicketHelper
def pretty_ticket_status(ticket)
status = ticket.status
if status == "partial"
"Under Investigation"
elsif status == "approved"
"Investigated"
else
status.titleize
end
end
end

View File

@ -1,12 +1,12 @@
import Uploader from './uploader.vue';
import Vue from 'vue';
export default {
init() {
const app = new Vue({
render: (h) => h(Uploader)
});
app.$mount('#uploader');
}
}
import Uploader from './uploader.vue';
import Vue from 'vue';
export default {
init() {
const app = new Vue({
render: (h) => h(Uploader)
});
app.$mount('#uploader');
}
}

View File

@ -1,24 +1,24 @@
<template>
<button class="toggle-button" :class="{active: value}" @click="value = !value">{{check.name}}</button>
</template>
<script>
export default {
props: ['check', 'checks'],
computed: {
value: {
get() {
if (this.checks[this.tagName] === undefined)
return false;
return this.checks[this.tagName];
},
set(v) {
this.$emit('set', this.tagName, v);
}
},
tagName() {
return this.check.tag || this.check.name.toLowerCase().replace(/ /g, '_');
}
}
}
</script>
<template>
<button class="toggle-button" :class="{active: value}" @click="value = !value">{{check.name}}</button>
</template>
<script>
export default {
props: ['check', 'checks'],
computed: {
value: {
get() {
if (this.checks[this.tagName] === undefined)
return false;
return this.checks[this.tagName];
},
set(v) {
this.$emit('set', this.tagName, v);
}
},
tagName() {
return this.check.tag || this.check.name.toLowerCase().replace(/ /g, '_');
}
}
}
</script>

View File

@ -1,70 +1,70 @@
<template>
<div>
<div v-show="loading">Fetching tags...</div>
<div class="related-tags flex-wrap">
<div class="related-items" v-for="sTags, i in splitTags" :key="i">
<tag-preview v-for="tag, $idx in sTags" :key="$idx" :tag="tag"></tag-preview>
</div>
</div>
<div>
<a href="#" @click.prevent="close">Close Preview</a>
</div>
</div>
</template>
<script>
import Vue from 'vue';
const tagPreviewTag = Vue.extend({
functional: true,
props: ['tag'],
render: function (h, ctx) {
var tag = ctx.props.tag;
switch (tag.type) {
default:
case 'tag':
return h('a', {
staticClass: 'tag-preview tag-type-' + tag.tagType
}, tag.a);
case 'alias':
return h('span', {staticClass: 'tag-preview tag-preview-alias'}, [
h('del', undefined, [
h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.a)
]), ' → ', h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.b)
]);
case 'implication':
return h('span', {staticClass: 'tag-preview tag-preview-implication'}, [
h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.a), ' ⇐ ', h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.b)
]);
}
}
});
export default {
props: ['tags', 'loading'],
components: {
'tag-preview': tagPreviewTag
},
methods: {
close: function () {
this.$emit('close');
}
},
computed: {
splitTags: function () {
var newTags = this.tags.concat([]);
newTags.sort(function (a, b) {
return a.a === b.a ? 0 : (a.a < b.a ? -1 : 1);
});
var chunkArray = function (arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
};
return chunkArray(newTags, 15);
}
}
}
</script>
<template>
<div>
<div v-show="loading">Fetching tags...</div>
<div class="related-tags flex-wrap">
<div class="related-items" v-for="sTags, i in splitTags" :key="i">
<tag-preview v-for="tag, $idx in sTags" :key="$idx" :tag="tag"></tag-preview>
</div>
</div>
<div>
<a href="#" @click.prevent="close">Close Preview</a>
</div>
</div>
</template>
<script>
import Vue from 'vue';
const tagPreviewTag = Vue.extend({
functional: true,
props: ['tag'],
render: function (h, ctx) {
var tag = ctx.props.tag;
switch (tag.type) {
default:
case 'tag':
return h('a', {
staticClass: 'tag-preview tag-type-' + tag.tagType
}, tag.a);
case 'alias':
return h('span', {staticClass: 'tag-preview tag-preview-alias'}, [
h('del', undefined, [
h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.a)
]), ' → ', h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.b)
]);
case 'implication':
return h('span', {staticClass: 'tag-preview tag-preview-implication'}, [
h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.a), ' ⇐ ', h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.b)
]);
}
}
});
export default {
props: ['tags', 'loading'],
components: {
'tag-preview': tagPreviewTag
},
methods: {
close: function () {
this.$emit('close');
}
},
computed: {
splitTags: function () {
var newTags = this.tags.concat([]);
newTags.sort(function (a, b) {
return a.a === b.a ? 0 : (a.a < b.a ? -1 : 1);
});
var chunkArray = function (arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
};
return chunkArray(newTags, 15);
}
}
}
</script>

View File

@ -1,89 +1,89 @@
<template>
<div class="related-tags flex-wrap">
<div class="related-section" v-for="group in tagGroups" :key="group.title">
<div class="related-items" v-for="tags, i in splitTags(group.tags)" :key="i">
<div class="related-title" v-if="i === 0">{{group.title}}</div>
<div class="related-item" v-for="tag in tags" :key="tag[0]">
<a :class="tagClasses(tag)" :href="tagLink(tag)" @click.prevent="toggle(tag)">{{tag[0]}}</a>
</div>
</div>
</div>
</div>
</template>
<script>
function tagSorter(a, b) {
return a[0] > b[0] ? 1 : -1;
}
export default {
props: ['tags', 'related', 'loading'],
data: function () {
return {
uploaded: (window.uploaderSettings.uploadTags || []),
recent: (window.uploaderSettings.recentTags || []).sort(tagSorter),
artists: (window.uploaderSettings.artistTags || []).sort(tagSorter)
};
},
methods: {
toggle: function (tag) {
this.$emit('tag-active', tag[0], !this.tagActive(tag));
},
tagLink: function (tag) {
return '/post/index?tags=' + encodeURIComponent(tag[0]);
},
tagActive: function (tag) {
return this.tags.indexOf(tag[0]) !== -1;
},
tagClasses: function (tag) {
var classes = {'tag-active': this.tagActive(tag)};
classes['tag-type-' + tag[2]] = true;
return classes;
},
splitTags: function (tags) {
var chunkArray = function (arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
};
return chunkArray(tags, 15);
}
},
computed: {
tagGroups: {
get: function () {
const groups = [];
if (this.uploaded && this.uploaded.length) {
groups.push({
title: "Quick Tags",
tags: this.uploaded
});
}
if (this.recent && this.recent.length) {
groups.push({
title: "Recent",
tags: this.recent
});
}
if (this.artists && this.artists.length) {
groups.push({
title: "Artists",
tags: this.artists
});
}
if (this.related && this.related.length) {
for (let i = 0; i < this.related.length; i++) {
groups.push(this.related[i]);
}
}
if (this.loading) {
groups.push({title: 'Loading Related Tags', tags: [['', '', '']]});
}
return groups;
}
}
}
}
</script>
<template>
<div class="related-tags flex-wrap">
<div class="related-section" v-for="group in tagGroups" :key="group.title">
<div class="related-items" v-for="tags, i in splitTags(group.tags)" :key="i">
<div class="related-title" v-if="i === 0">{{group.title}}</div>
<div class="related-item" v-for="tag in tags" :key="tag[0]">
<a :class="tagClasses(tag)" :href="tagLink(tag)" @click.prevent="toggle(tag)">{{tag[0]}}</a>
</div>
</div>
</div>
</div>
</template>
<script>
function tagSorter(a, b) {
return a[0] > b[0] ? 1 : -1;
}
export default {
props: ['tags', 'related', 'loading'],
data: function () {
return {
uploaded: (window.uploaderSettings.uploadTags || []),
recent: (window.uploaderSettings.recentTags || []).sort(tagSorter),
artists: (window.uploaderSettings.artistTags || []).sort(tagSorter)
};
},
methods: {
toggle: function (tag) {
this.$emit('tag-active', tag[0], !this.tagActive(tag));
},
tagLink: function (tag) {
return '/post/index?tags=' + encodeURIComponent(tag[0]);
},
tagActive: function (tag) {
return this.tags.indexOf(tag[0]) !== -1;
},
tagClasses: function (tag) {
var classes = {'tag-active': this.tagActive(tag)};
classes['tag-type-' + tag[2]] = true;
return classes;
},
splitTags: function (tags) {
var chunkArray = function (arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
};
return chunkArray(tags, 15);
}
},
computed: {
tagGroups: {
get: function () {
const groups = [];
if (this.uploaded && this.uploaded.length) {
groups.push({
title: "Quick Tags",
tags: this.uploaded
});
}
if (this.recent && this.recent.length) {
groups.push({
title: "Recent",
tags: this.recent
});
}
if (this.artists && this.artists.length) {
groups.push({
title: "Artists",
tags: this.artists
});
}
if (this.related && this.related.length) {
for (let i = 0; i < this.related.length; i++) {
groups.push(this.related[i]);
}
}
if (this.loading) {
groups.push({title: 'Loading Related Tags', tags: [['', '', '']]});
}
return groups;
}
}
}
}
</script>

View File

@ -1,3 +1,3 @@
@function border_color($color) {
@return darken($color, 25%);
}
@function border_color($color) {
@return darken($color, 25%);
}

View File

@ -1,3 +1,3 @@
.comment-vote-down-link, .comment-vote-up-link, .post-vote-up-link, .post-vote-down-link {
cursor: pointer;
}
.comment-vote-down-link, .comment-vote-up-link, .post-vote-up-link, .post-vote-down-link {
cursor: pointer;
}

View File

@ -2,4 +2,4 @@
.section {
margin-bottom: 2em;
}
}
}

View File

@ -2,4 +2,4 @@ div#c-maintenance-user-login-reminders {
div#a-new {
width: 50em;
}
}
}

View File

@ -2,4 +2,4 @@
section {
margin-bottom: 2em;
}
}
}

View File

@ -7,4 +7,4 @@ div#c-maintenance-user-deletions {
li {
list-style-type: disc;
}
}
}

View File

@ -1,9 +1,9 @@
class IqdbRemoveJob
include Sidekiq::Worker
sidekiq_options queue: 'iqdb'
def perform(post_id)
# STUB: The implementation of this is performed by the iqdb component.
end
end
class IqdbRemoveJob
include Sidekiq::Worker
sidekiq_options queue: 'iqdb'
def perform(post_id)
# STUB: The implementation of this is performed by the iqdb component.
end
end

View File

@ -1,9 +1,9 @@
class IqdbUpdateJob
include Sidekiq::Worker
sidekiq_options queue: 'iqdb'
def perform(post_id, thumbnail_url)
# STUB: The implementation of this is performed by the iqdb component.
end
end
class IqdbUpdateJob
include Sidekiq::Worker
sidekiq_options queue: 'iqdb'
def perform(post_id, thumbnail_url)
# STUB: The implementation of this is performed by the iqdb component.
end
end

View File

@ -1,8 +1,8 @@
class TagAliasUndoJob < ApplicationJob
queue_as :tags
def perform(*args)
ta = TagAlias.find(args[0])
ta.process_undo!(update_topic: args[1])
end
end
class TagAliasUndoJob < ApplicationJob
queue_as :tags
def perform(*args)
ta = TagAlias.find(args[0])
ta.process_undo!(update_topic: args[1])
end
end

View File

@ -1,18 +1,18 @@
class TransferFavoritesJob < ApplicationJob
queue_as :low_prio
def perform(*args)
without_mod_action = args[2]
@post = Post.find_by(id: args[0])
@user = User.find_by(id: args[1])
unless @post && @user
# Something went wrong and there is nothing we can do inside the job.
return
end
CurrentUser.as(@user) do
@post.give_favorites_to_parent!(without_mod_action: without_mod_action)
end
end
end
class TransferFavoritesJob < ApplicationJob
queue_as :low_prio
def perform(*args)
without_mod_action = args[2]
@post = Post.find_by(id: args[0])
@user = User.find_by(id: args[1])
unless @post && @user
# Something went wrong and there is nothing we can do inside the job.
return
end
CurrentUser.as(@user) do
@post.give_favorites_to_parent!(without_mod_action: without_mod_action)
end
end
end

View File

@ -1,7 +1,7 @@
class AdminRouteConstraint
def matches?(request)
return false unless request.session[:user_id]
user = User.find(request.session[:user_id])
user && user.is_admin?
end
end
class AdminRouteConstraint
def matches?(request)
return false unless request.session[:user_id]
user = User.find(request.session[:user_id])
user && user.is_admin?
end
end

View File

@ -1,50 +1,50 @@
class BulkRelatedTagQuery
include ActiveModel::Serializers::JSON
include ActiveModel::Serializers::Xml
attr_reader :query, :category, :user
def initialize(query: nil, category: nil, user: nil)
@user = user
@query = Tag.normalize_query(query).split(' ').slice(0, 25)
@category = category
end
def tags
if category.present?
related_tags_by_category
elsif query.present?
related_tags
else
{}
end
end
def serializable_hash(**options)
tags
end
protected
def related_tags
@related_tags ||= Tag.where(name: @query).each_with_object({}) do |tag, hash|
related = tag.related_tag_array
categories = Tag.categories_for(related.map(&:first))
hash[tag.name] = related.map {|name, count| [name, count.to_i, categories.fetch(name, -1)]}
end
end
def related_tags_by_category
@related_tags_by_category ||= begin
cat = Tag.categories.value_for(category)
@query.each_with_object({}) do |tag, hash|
related = RelatedTagCalculator.calculate_from_sample_to_array(tag, cat)
categories = Tag.categories_for(related.map(&:first))
hash[tag] = related.map {|name, count| [name, count.to_i, categories.fetch(name, -1)]}
end
end
end
end
class BulkRelatedTagQuery
include ActiveModel::Serializers::JSON
include ActiveModel::Serializers::Xml
attr_reader :query, :category, :user
def initialize(query: nil, category: nil, user: nil)
@user = user
@query = Tag.normalize_query(query).split(' ').slice(0, 25)
@category = category
end
def tags
if category.present?
related_tags_by_category
elsif query.present?
related_tags
else
{}
end
end
def serializable_hash(**options)
tags
end
protected
def related_tags
@related_tags ||= Tag.where(name: @query).each_with_object({}) do |tag, hash|
related = tag.related_tag_array
categories = Tag.categories_for(related.map(&:first))
hash[tag.name] = related.map {|name, count| [name, count.to_i, categories.fetch(name, -1)]}
end
end
def related_tags_by_category
@related_tags_by_category ||= begin
cat = Tag.categories.value_for(category)
@query.each_with_object({}) do |tag, hash|
related = RelatedTagCalculator.calculate_from_sample_to_array(tag, cat)
categories = Tag.categories_for(related.map(&:first))
hash[tag] = related.map {|name, count| [name, count.to_i, categories.fetch(name, -1)]}
end
end
end
end

View File

@ -36,4 +36,4 @@ module Danbooru
end
end
end
end
end

View File

@ -1,22 +1,22 @@
class EmailLinkValidator
def self.generate(message, purpose, expires = nil)
validator.generate(message, purpose: purpose, expires_in: expires)
end
def self.validate(hash, purpose)
begin
message = validator.verify(hash, purpose: purpose)
return false if message.nil?
return message
rescue
return false
end
end
private
def self.validator
@validator ||= ActiveSupport::MessageVerifier.new(Danbooru.config.email_key, serializer: JSON, hash: "SHA256")
end
end
class EmailLinkValidator
def self.generate(message, purpose, expires = nil)
validator.generate(message, purpose: purpose, expires_in: expires)
end
def self.validate(hash, purpose)
begin
message = validator.verify(hash, purpose: purpose)
return false if message.nil?
return message
rescue
return false
end
end
private
def self.validator
@validator ||= ActiveSupport::MessageVerifier.new(Danbooru.config.email_key, serializer: JSON, hash: "SHA256")
end
end

View File

@ -1,80 +1,80 @@
# Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
# Copyright (c) 2013, Taylor Hornby
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'securerandom'
require 'openssl'
require 'base64'
module Pbkdf2
PBKDF2_ITERATIONS = 20000
SALT_BYTE_SIZE = 24
HASH_BYTE_SIZE = 24
HASH_SECTIONS = 4
SECTION_DELIMITER = ':'
ITERATIONS_INDEX = 1
SALT_INDEX = 2
HASH_INDEX = 3
def self.create_hash( password )
salt = SecureRandom.base64( SALT_BYTE_SIZE )
pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
password,
salt,
PBKDF2_ITERATIONS,
HASH_BYTE_SIZE
)
return ["sha1", PBKDF2_ITERATIONS, salt, Base64.encode64( pbkdf2 )].join( SECTION_DELIMITER )
end
def self.validate_password( password, correctHash )
params = correctHash.split( SECTION_DELIMITER )
return false if params.length != HASH_SECTIONS
pbkdf2 = Base64.decode64( params[HASH_INDEX] )
testHash = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
password,
params[SALT_INDEX],
params[ITERATIONS_INDEX].to_i,
pbkdf2.length
)
return pbkdf2 == testHash
end
def self.needs_upgrade( hash )
params = hash.split( SECTION_DELIMITER )
if params.length != HASH_SECTIONS
return true
end
if params[ITERATIONS_INDEX] != PBKDF2_ITERATIONS.to_s
return true
end
return false
end
end
# Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
# Copyright (c) 2013, Taylor Hornby
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'securerandom'
require 'openssl'
require 'base64'
module Pbkdf2
PBKDF2_ITERATIONS = 20000
SALT_BYTE_SIZE = 24
HASH_BYTE_SIZE = 24
HASH_SECTIONS = 4
SECTION_DELIMITER = ':'
ITERATIONS_INDEX = 1
SALT_INDEX = 2
HASH_INDEX = 3
def self.create_hash( password )
salt = SecureRandom.base64( SALT_BYTE_SIZE )
pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
password,
salt,
PBKDF2_ITERATIONS,
HASH_BYTE_SIZE
)
return ["sha1", PBKDF2_ITERATIONS, salt, Base64.encode64( pbkdf2 )].join( SECTION_DELIMITER )
end
def self.validate_password( password, correctHash )
params = correctHash.split( SECTION_DELIMITER )
return false if params.length != HASH_SECTIONS
pbkdf2 = Base64.decode64( params[HASH_INDEX] )
testHash = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
password,
params[SALT_INDEX],
params[ITERATIONS_INDEX].to_i,
pbkdf2.length
)
return pbkdf2 == testHash
end
def self.needs_upgrade( hash )
params = hash.split( SECTION_DELIMITER )
if params.length != HASH_SECTIONS
return true
end
if params[ITERATIONS_INDEX] != PBKDF2_ITERATIONS.to_s
return true
end
return false
end
end

View File

@ -1,24 +1,24 @@
class RateLimiter
def self.check_limit(key, max_attempts, lockout_time = 1.minute)
return true if Cache.get("#{key}:lockout")
attempts = Cache.get(key) || 0
if attempts >= max_attempts
Cache.put("#{key}:lockout", true, lockout_time)
reset_limit(key)
return true
end
false
end
def self.hit(key, time_period = 1.minute)
value = Cache.get(key) || 0
Cache.put(key, value.to_i + 1, time_period)
return value.to_i + 1
end
def self.reset_limit(key)
Cache.delete(key)
end
end
class RateLimiter
def self.check_limit(key, max_attempts, lockout_time = 1.minute)
return true if Cache.get("#{key}:lockout")
attempts = Cache.get(key) || 0
if attempts >= max_attempts
Cache.put("#{key}:lockout", true, lockout_time)
reset_limit(key)
return true
end
false
end
def self.hit(key, time_period = 1.minute)
value = Cache.get(key) || 0
Cache.put(key, value.to_i + 1, time_period)
return value.to_i + 1
end
def self.reset_limit(key)
Cache.delete(key)
end
end

View File

@ -1,13 +1,13 @@
module Sources
module Alternates
def self.all
return [Alternates::Furaffinity,
Alternates::Pixiv]
end
def self.find(url, default: Alternates::Null)
alternate = all.map {|alternate| alternate.new(url)}.detect(&:match?)
alternate || default&.new(url)
end
end
end
module Sources
module Alternates
def self.all
return [Alternates::Furaffinity,
Alternates::Pixiv]
end
def self.find(url, default: Alternates::Null)
alternate = all.map {|alternate| alternate.new(url)}.detect(&:match?)
alternate || default&.new(url)
end
end
end

View File

@ -1,23 +1,23 @@
module Sources
module Alternates
class Furaffinity < Base
IMAGE_TO_ARTIST = /facdn\.net\/art\/([0-9a-zA-Z_.~\-]+)/
SUBMISSION_URL = /furaffinity\.net\/view\/(\d+)/
def force_https?
true
end
def domains
["furaffinity.net", "facdn.net"]
end
def parse
if @url =~ IMAGE_TO_ARTIST
@gallery_url = "https://www.furaffinity.net/user/#{$1}/"
@direct_url = @url
end
end
end
end
end
module Sources
module Alternates
class Furaffinity < Base
IMAGE_TO_ARTIST = /facdn\.net\/art\/([0-9a-zA-Z_.~\-]+)/
SUBMISSION_URL = /furaffinity\.net\/view\/(\d+)/
def force_https?
true
end
def domains
["furaffinity.net", "facdn.net"]
end
def parse
if @url =~ IMAGE_TO_ARTIST
@gallery_url = "https://www.furaffinity.net/user/#{$1}/"
@direct_url = @url
end
end
end
end
end

View File

@ -1,7 +1,7 @@
module Sources
module Alternates
class Null < Base
end
end
end
module Sources
module Alternates
class Null < Base
end
end
end

View File

@ -1,70 +1,70 @@
# Pixiv
#
# * https://i.pximg.net/img-original/img/2014/10/03/18/10/20/46324488_p0.png
#
# * https://i.pximg.net/c/250x250_80_a2/img-master/img/2014/10/29/09/27/19/46785915_p0_square1200.jpg
# * https://i.pximg.net/img-master/img/2014/10/03/18/10/20/46324488_p0_master1200.jpg
#
# * https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46324488
# * https://www.pixiv.net/member_illust.php?mode=manga&illust_id=46324488
# * https://www.pixiv.net/member_illust.php?mode=manga_big&illust_id=46324488&page=0
#
# * https://www.pixiv.net/member.php?id=339253
# * https://www.pixiv.net/member_illust.php?id=339253&type=illust
# * https://www.pixiv.net/u/9202877
# * https://www.pixiv.net/stacc/noizave
# * http://www.pixiv.me/noizave
#
# Fanbox
#
# * https://fanbox.pixiv.net/images/post/39714/JvjJal8v1yLgc5DPyEI05YpT.png
# * https://pixiv.pximg.net/fanbox/public/images/creator/1566167/profile/Ix6bnJmTaOAFZhXHLbWyIY1e.jpeg
#
# * https://pixiv.pximg.net/c/400x400_90_a2_g5/fanbox/public/images/creator/1566167/profile/Ix6bnJmTaOAFZhXHLbWyIY1e.jpeg
# * https://pixiv.pximg.net/c/1200x630_90_a2_g5/fanbox/public/images/post/186919/cover/VCI1Mcs2rbmWPg0mmiTisovn.jpeg
#
# * https://www.pixiv.net/fanbox/creator/1566167/post/39714
# * https://www.pixiv.net/fanbox/creator/1566167
#
# Novels
#
# * https://i.pximg.net/novel-cover-original/img/2019/01/14/01/15/05/10617324_d84daae89092d96bbe66efafec136e42.jpg
# * https://i.pximg.net/c/600x600/novel-cover-master/img/2019/01/14/01/15/05/10617324_d84daae89092d96bbe66efafec136e42_master1200.jpg
# * https://img-novel.pximg.net/img-novel/work_main/XtFbt7gsymsvyaG45lZ8/1554.jpg?20190107110435
#
# * https://www.pixiv.net/novel/show.php?id=10617324
# * https://novel.pixiv.net/works/1554
#
# Sketch
#
# * https://img-sketch.pixiv.net/uploads/medium/file/4463372/8906921629213362989.jpg
# * https://img-sketch.pximg.net/c!/w=540,f=webp:jpeg/uploads/medium/file/4463372/8906921629213362989.jpg
# * https://sketch.pixiv.net/items/1588346448904706151
# * https://sketch.pixiv.net/@0125840
#
module Sources
module Strategies
class PixivSlim < Base
def domains
["pixiv.net", "pximg.net"]
end
def site_name
"Pixiv"
end
def canonical_url
image_url
end
def image_urls
[url]
end
def headers
{ "Referer" => "https://www.pixiv.net"}
end
end
end
end
# Pixiv
#
# * https://i.pximg.net/img-original/img/2014/10/03/18/10/20/46324488_p0.png
#
# * https://i.pximg.net/c/250x250_80_a2/img-master/img/2014/10/29/09/27/19/46785915_p0_square1200.jpg
# * https://i.pximg.net/img-master/img/2014/10/03/18/10/20/46324488_p0_master1200.jpg
#
# * https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46324488
# * https://www.pixiv.net/member_illust.php?mode=manga&illust_id=46324488
# * https://www.pixiv.net/member_illust.php?mode=manga_big&illust_id=46324488&page=0
#
# * https://www.pixiv.net/member.php?id=339253
# * https://www.pixiv.net/member_illust.php?id=339253&type=illust
# * https://www.pixiv.net/u/9202877
# * https://www.pixiv.net/stacc/noizave
# * http://www.pixiv.me/noizave
#
# Fanbox
#
# * https://fanbox.pixiv.net/images/post/39714/JvjJal8v1yLgc5DPyEI05YpT.png
# * https://pixiv.pximg.net/fanbox/public/images/creator/1566167/profile/Ix6bnJmTaOAFZhXHLbWyIY1e.jpeg
#
# * https://pixiv.pximg.net/c/400x400_90_a2_g5/fanbox/public/images/creator/1566167/profile/Ix6bnJmTaOAFZhXHLbWyIY1e.jpeg
# * https://pixiv.pximg.net/c/1200x630_90_a2_g5/fanbox/public/images/post/186919/cover/VCI1Mcs2rbmWPg0mmiTisovn.jpeg
#
# * https://www.pixiv.net/fanbox/creator/1566167/post/39714
# * https://www.pixiv.net/fanbox/creator/1566167
#
# Novels
#
# * https://i.pximg.net/novel-cover-original/img/2019/01/14/01/15/05/10617324_d84daae89092d96bbe66efafec136e42.jpg
# * https://i.pximg.net/c/600x600/novel-cover-master/img/2019/01/14/01/15/05/10617324_d84daae89092d96bbe66efafec136e42_master1200.jpg
# * https://img-novel.pximg.net/img-novel/work_main/XtFbt7gsymsvyaG45lZ8/1554.jpg?20190107110435
#
# * https://www.pixiv.net/novel/show.php?id=10617324
# * https://novel.pixiv.net/works/1554
#
# Sketch
#
# * https://img-sketch.pixiv.net/uploads/medium/file/4463372/8906921629213362989.jpg
# * https://img-sketch.pximg.net/c!/w=540,f=webp:jpeg/uploads/medium/file/4463372/8906921629213362989.jpg
# * https://sketch.pixiv.net/items/1588346448904706151
# * https://sketch.pixiv.net/@0125840
#
module Sources
module Strategies
class PixivSlim < Base
def domains
["pixiv.net", "pximg.net"]
end
def site_name
"Pixiv"
end
def canonical_url
image_url
end
def image_urls
[url]
end
def headers
{ "Referer" => "https://www.pixiv.net"}
end
end
end
end

View File

@ -1,91 +1,91 @@
class TagCategory
module Mappings
# Returns a hash mapping various tag categories to a numerical value.
def mapping
@@mapping ||= Hash[
Danbooru.config.full_tag_config_info.map {|k,v| v["extra"].map {|y| [y,v["category"]]}}
.reduce([],:+)]
.update(Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["short"],v["category"]]}])
.update( Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["category"]]}])
end
# Returns a hash mapping more suited for views
def canonical_mapping
@@canonical_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k.capitalize,v["category"]]}]
end
# Returns a hash mapping numerical category values to their string equivalent.
def reverse_mapping
@@reverse_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["category"],k]}]
end
# Returns a hash mapping for the short name usage in metatags
def short_name_mapping
@@short_name_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["short"],k]}]
end
# Returns a hash mapping for humanized_essential_tag_string (models/post.rb)
def humanized_mapping
@@humanized_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["humanized"]]}]
end
# Returns a hash mapping for split_tag_list_html (presenters/tag_set_presenter.rb)
def header_mapping
@@header_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["header"]]}]
end
# Returns a hash mapping for related tag buttons (javascripts/related_tag.js.erb)
def related_button_mapping
@@related_button_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["relatedbutton"]]}]
end
def mod_only_mapping
@@mod_only_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["mod_only"] || false]}]
end
# Returns a hash mapping for CSS (stylesheets/posts.scss.erb)
def css_mapping
@@css_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["category"],v["css"]]}]
end
end
module Lists
def categories
@@categories ||= Danbooru.config.full_tag_config_info.keys
end
def category_ids
@@category_ids ||= canonical_mapping.values
end
def short_name_list
@@short_name_list ||= short_name_mapping.keys
end
def humanized_list
Danbooru.config.humanized_tag_category_list
end
def split_header_list
Danbooru.config.split_tag_header_list
end
def categorized_list
Danbooru.config.categorized_tag_list
end
def related_button_list
Danbooru.config.related_tag_button_list
end
end
module Regexes
def short_name_regex
@@short_name_regex ||= short_name_list.join("|")
end
end
extend Mappings
extend Lists
extend Regexes
end
class TagCategory
module Mappings
# Returns a hash mapping various tag categories to a numerical value.
def mapping
@@mapping ||= Hash[
Danbooru.config.full_tag_config_info.map {|k,v| v["extra"].map {|y| [y,v["category"]]}}
.reduce([],:+)]
.update(Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["short"],v["category"]]}])
.update( Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["category"]]}])
end
# Returns a hash mapping more suited for views
def canonical_mapping
@@canonical_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k.capitalize,v["category"]]}]
end
# Returns a hash mapping numerical category values to their string equivalent.
def reverse_mapping
@@reverse_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["category"],k]}]
end
# Returns a hash mapping for the short name usage in metatags
def short_name_mapping
@@short_name_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["short"],k]}]
end
# Returns a hash mapping for humanized_essential_tag_string (models/post.rb)
def humanized_mapping
@@humanized_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["humanized"]]}]
end
# Returns a hash mapping for split_tag_list_html (presenters/tag_set_presenter.rb)
def header_mapping
@@header_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["header"]]}]
end
# Returns a hash mapping for related tag buttons (javascripts/related_tag.js.erb)
def related_button_mapping
@@related_button_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["relatedbutton"]]}]
end
def mod_only_mapping
@@mod_only_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [k,v["mod_only"] || false]}]
end
# Returns a hash mapping for CSS (stylesheets/posts.scss.erb)
def css_mapping
@@css_mapping ||= Hash[Danbooru.config.full_tag_config_info.map {|k,v| [v["category"],v["css"]]}]
end
end
module Lists
def categories
@@categories ||= Danbooru.config.full_tag_config_info.keys
end
def category_ids
@@category_ids ||= canonical_mapping.values
end
def short_name_list
@@short_name_list ||= short_name_mapping.keys
end
def humanized_list
Danbooru.config.humanized_tag_category_list
end
def split_header_list
Danbooru.config.split_tag_header_list
end
def categorized_list
Danbooru.config.categorized_tag_list
end
def related_button_list
Danbooru.config.related_tag_button_list
end
end
module Regexes
def short_name_regex
@@short_name_regex ||= short_name_list.join("|")
end
end
extend Mappings
extend Lists
extend Regexes
end

View File

@ -1,41 +1,41 @@
class TagsPreview
def initialize(tags: nil)
@tags = Tag.scan_tags(tags).map {|x| {a: x, type: 'tag'}}
aliases
implications
tag_types
end
def aliases
names = @tags.map{ |tag| tag[:a] }.reject {|y| y.blank?}
aliased = TagAlias.to_aliased_with_originals(names).reject {|k,v| k == v }
@tags.map! do |tag|
if aliased[tag[:a]]
{a: tag[:a], b: aliased[tag[:a]], type: 'alias'}
else
tag
end
end
end
def implications
names = @tags.map {|tag| tag[:b] || tag[:a] }
implications = TagImplication.descendants_with_originals(names)
implications.each do |implication, descendants|
@tags += descendants.map { |descendant| {a: implication, b: descendant, type: 'implication'} }
end
end
def tag_types
names = @tags.map { |tag| tag[:b] || tag[:a] }
categories = Tag.categories_for(names)
@tags.map! do |tag|
tag[:tagType] = categories.fetch(tag[:b] || tag[:a], -1)
tag
end
end
def serializable_hash(**options)
@tags
end
end
class TagsPreview
def initialize(tags: nil)
@tags = Tag.scan_tags(tags).map {|x| {a: x, type: 'tag'}}
aliases
implications
tag_types
end
def aliases
names = @tags.map{ |tag| tag[:a] }.reject {|y| y.blank?}
aliased = TagAlias.to_aliased_with_originals(names).reject {|k,v| k == v }
@tags.map! do |tag|
if aliased[tag[:a]]
{a: tag[:a], b: aliased[tag[:a]], type: 'alias'}
else
tag
end
end
end
def implications
names = @tags.map {|tag| tag[:b] || tag[:a] }
implications = TagImplication.descendants_with_originals(names)
implications.each do |implication, descendants|
@tags += descendants.map { |descendant| {a: implication, b: descendant, type: 'implication'} }
end
end
def tag_types
names = @tags.map { |tag| tag[:b] || tag[:a] }
categories = Tag.categories_for(names)
@tags.map! do |tag|
tag[:tagType] = categories.fetch(tag[:b] || tag[:a], -1)
tag
end
end
def serializable_hash(**options)
@tags
end
end

View File

@ -1,79 +1,79 @@
class UserThrottle
def initialize(options, user)
@prefix = options[:prefix] || "thtl:"
@duration = options[:duration] || 1.minute
@user_id = user.id
@max_rate = options[:max] || user.api_burst_limit
@cached_rate = 0
end
def accept?
(@max_rate - current_rate) > 0
end
def cached_count
@max_rate - @cached_rate
end
def uncached_count
@max_rate - current_rate
end
def throttled?
if accept?
hit!
false
else
true
end
end
private
def cache_duration
(@duration / 60.seconds).to_i + 1
end
def current_rate
t = Time.now
ckey = current_key(t)
pkey = previous_key(t)
tdiff = t.to_i - ctime(t)*@duration.to_i
hits = redis_client.mget(ckey, pkey)
@cached_rate = (hits[1].to_f * ((@duration.to_i-tdiff)/@duration.to_f) + hits[0].to_f).to_i
end
def hit!
t = Time.now
ckey = current_key(t)
redis_client.multi do
redis_client.incr(ckey)
redis_client.expire(ckey, cache_duration.minutes)
end
end
def current_key(t)
"#{throttle_prefix}#{ctime(t)}"
end
def previous_key(t)
"#{throttle_prefix}#{ptime(t)}"
end
def ctime(t)
((t.to_i / @duration.to_i)).to_i
end
def ptime(t)
((t.to_i / @duration.to_i) - 1).to_i
end
def throttle_prefix
"#{@prefix}#{@user_id}:"
end
def redis_client
@@client ||= ::Redis.new(url: Danbooru.config.redis_url)
end
end
class UserThrottle
def initialize(options, user)
@prefix = options[:prefix] || "thtl:"
@duration = options[:duration] || 1.minute
@user_id = user.id
@max_rate = options[:max] || user.api_burst_limit
@cached_rate = 0
end
def accept?
(@max_rate - current_rate) > 0
end
def cached_count
@max_rate - @cached_rate
end
def uncached_count
@max_rate - current_rate
end
def throttled?
if accept?
hit!
false
else
true
end
end
private
def cache_duration
(@duration / 60.seconds).to_i + 1
end
def current_rate
t = Time.now
ckey = current_key(t)
pkey = previous_key(t)
tdiff = t.to_i - ctime(t)*@duration.to_i
hits = redis_client.mget(ckey, pkey)
@cached_rate = (hits[1].to_f * ((@duration.to_i-tdiff)/@duration.to_f) + hits[0].to_f).to_i
end
def hit!
t = Time.now
ckey = current_key(t)
redis_client.multi do
redis_client.incr(ckey)
redis_client.expire(ckey, cache_duration.minutes)
end
end
def current_key(t)
"#{throttle_prefix}#{ctime(t)}"
end
def previous_key(t)
"#{throttle_prefix}#{ptime(t)}"
end
def ctime(t)
((t.to_i / @duration.to_i)).to_i
end
def ptime(t)
((t.to_i / @duration.to_i) - 1).to_i
end
def throttle_prefix
"#{@prefix}#{@user_id}:"
end
def redis_client
@@client ||= ::Redis.new(url: Danbooru.config.redis_url)
end
end

View File

@ -1,14 +1,14 @@
module Maintenance
module User
class EmailConfirmationMailer < ActionMailer::Base
add_template_helper ApplicationHelper
add_template_helper UsersHelper
default :from => Danbooru.config.mail_from_addr, :content_type => "text/html"
def confirmation(user)
@user = user
mail(:to => @user.email, :subject => "#{Danbooru.config.app_name} account confirmation")
end
end
end
end
module Maintenance
module User
class EmailConfirmationMailer < ActionMailer::Base
add_template_helper ApplicationHelper
add_template_helper UsersHelper
default :from => Danbooru.config.mail_from_addr, :content_type => "text/html"
def confirmation(user)
@user = user
mail(:to => @user.email, :subject => "#{Danbooru.config.app_name} account confirmation")
end
end
end
end

View File

@ -1,14 +1,14 @@
class EditHistory < ApplicationRecord
self.table_name = 'edit_histories'
belongs_to :versionable, polymorphic: true
belongs_to :user
attr_accessor :difference
TYPE_MAP = {
comment: 'Comment',
forum: 'ForumPost',
blip: 'Blip'
}
end
class EditHistory < ApplicationRecord
self.table_name = 'edit_histories'
belongs_to :versionable, polymorphic: true
belongs_to :user
attr_accessor :difference
TYPE_MAP = {
comment: 'Comment',
forum: 'ForumPost',
blip: 'Blip'
}
end

View File

@ -15,4 +15,4 @@ class PostReportReason < ApplicationRecord
reasons.each {|x| js_map[x.id] = x.description}
js_map
end
end
end

View File

@ -1,149 +1,149 @@
class PostSetMaintainer < ApplicationRecord
belongs_to :user
belongs_to :post_set
validate :ensure_not_set_owner, on: :create
validate :ensure_set_public, on: :create
validate :ensure_maintainer_count, on: :create
validate :ensure_not_duplicate, on: :create
after_create :notify_maintainer
def notify_maintainer
body = "\"#{post_set.creator.name}\":/users/#{post_set.creator_id} invited you to be a maintainer of the \"#{post_set.name}\":/post_sets/#{post_set_id} set. This would allow you to add and remove posts from it.
\"Click here\":/post_set_maintainers/#{id}/approve to approve the request and become a maintainer.
\"Click here\":/post_set_maintainers/#{id}/deny to deny the request.
\"Click here\":/post_set_maintainers/#{id}/block to deny the request and prevent yourself from being invited to this set again in the future."
Dmail.create_automated(
to_id: user_id,
title: "You were invite to be a maintainer of #{post_set.name}",
body: body
)
end
def notify_destroy
end
def cancel!
if status == 'pending'
self.status = 'cooldown'
save
return
end
if status == 'approved'
body = "\"#{post_set.creator.name}\":/users/#{post_set.creator_id} removed you as a maintainer of the \"#{post_set.name}\":/post_sets/#{post_set.id} set."
Dmail.create_automated(
to_id: user_id,
title: "You were removed as a set maintainer of #{post_set.name}",
body: body
)
end
destroy
end
def approve!
self.status = 'approved'
save
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} approved your invite to maintain #{post_set.name}",
body: "\"#{user.name}\":/users/#{user_id} approved your invite to maintain \"#{post_set.name}\":/post_sets/#{post_set.id}."
)
end
def deny!
if status == "pending"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} denied your invite to maintain #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} denied your invite to maintain \"#{post_set.name}\":/post_sets/#{post_set.id}."
)
elsif status == "approved"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} removed themselves as a maintainer of #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} removed themselves as a maintainer of \"#{post_set.name}\":/post_sets/#{post_set.id}."
)
end
destroy
end
def block!
if status == "approved"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} removed themselves as a maintainer of #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} removed themselves as a maintainer of \"#{post_set.name}\":/post_sets/#{post_set.id} and blocked all future invites."
)
elsif status == "pending"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} denied your invite to maintain #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} denied your invite to maintain \"#{post_set.name}\":/post_sets/#{post_set.id} and blocked all future invites."
)
end
self.status = 'blocked'
save
end
module ValidaitonMethods
def ensure_not_set_owner
if post_set.creator_id == user_id
errors.add(:user, "owns this set and can't be added as a maintainer")
false
end
end
def ensure_maintainer_count
if PostSetMaintainer.where(post_set_id: post_set_id).count >= 75
errors.add(:post_set, "current have too many maintainers")
false
end
end
def ensure_not_duplicate
existing = PostSetMaintainer.where(post_set_id: post_set_id, user_id: user_id).first
if existing.nil?
return
end
if ['approved', 'pending'].include?(existing.status)
errors.add(:base, "Already a maintainer of this set")
return false
end
if existing.status == 'blocked'
errors.add(:base, 'User has blocked you from inviting them to maintain this set')
return false
end
if existing.status == 'cooldown' && existing.created_at > 24.hours.ago
errors.add(:base, "User has been invited to maintain this set too recently")
return false
end
end
def ensure_set_public
unless post_set.is_public
errors.add(:post_set, 'must be public')
false
end
end
end
def maintained(user)
where(user_id: user.id, status: 'approved').joins(:post_set).where('post_set.is_public = true')
end
def self.active
where(status: 'approved')
end
def self.pending
where(status: 'pending')
end
include ValidaitonMethods
end
class PostSetMaintainer < ApplicationRecord
belongs_to :user
belongs_to :post_set
validate :ensure_not_set_owner, on: :create
validate :ensure_set_public, on: :create
validate :ensure_maintainer_count, on: :create
validate :ensure_not_duplicate, on: :create
after_create :notify_maintainer
def notify_maintainer
body = "\"#{post_set.creator.name}\":/users/#{post_set.creator_id} invited you to be a maintainer of the \"#{post_set.name}\":/post_sets/#{post_set_id} set. This would allow you to add and remove posts from it.
\"Click here\":/post_set_maintainers/#{id}/approve to approve the request and become a maintainer.
\"Click here\":/post_set_maintainers/#{id}/deny to deny the request.
\"Click here\":/post_set_maintainers/#{id}/block to deny the request and prevent yourself from being invited to this set again in the future."
Dmail.create_automated(
to_id: user_id,
title: "You were invite to be a maintainer of #{post_set.name}",
body: body
)
end
def notify_destroy
end
def cancel!
if status == 'pending'
self.status = 'cooldown'
save
return
end
if status == 'approved'
body = "\"#{post_set.creator.name}\":/users/#{post_set.creator_id} removed you as a maintainer of the \"#{post_set.name}\":/post_sets/#{post_set.id} set."
Dmail.create_automated(
to_id: user_id,
title: "You were removed as a set maintainer of #{post_set.name}",
body: body
)
end
destroy
end
def approve!
self.status = 'approved'
save
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} approved your invite to maintain #{post_set.name}",
body: "\"#{user.name}\":/users/#{user_id} approved your invite to maintain \"#{post_set.name}\":/post_sets/#{post_set.id}."
)
end
def deny!
if status == "pending"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} denied your invite to maintain #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} denied your invite to maintain \"#{post_set.name}\":/post_sets/#{post_set.id}."
)
elsif status == "approved"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} removed themselves as a maintainer of #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} removed themselves as a maintainer of \"#{post_set.name}\":/post_sets/#{post_set.id}."
)
end
destroy
end
def block!
if status == "approved"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} removed themselves as a maintainer of #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} removed themselves as a maintainer of \"#{post_set.name}\":/post_sets/#{post_set.id} and blocked all future invites."
)
elsif status == "pending"
Dmail.create_automated(
to_id: post_set.creator_id,
title: "#{user.name} denied your invite to maintain #{post_set.name}",
body: "\"#{user.name}\":/users/#{user.id} denied your invite to maintain \"#{post_set.name}\":/post_sets/#{post_set.id} and blocked all future invites."
)
end
self.status = 'blocked'
save
end
module ValidaitonMethods
def ensure_not_set_owner
if post_set.creator_id == user_id
errors.add(:user, "owns this set and can't be added as a maintainer")
false
end
end
def ensure_maintainer_count
if PostSetMaintainer.where(post_set_id: post_set_id).count >= 75
errors.add(:post_set, "current have too many maintainers")
false
end
end
def ensure_not_duplicate
existing = PostSetMaintainer.where(post_set_id: post_set_id, user_id: user_id).first
if existing.nil?
return
end
if ['approved', 'pending'].include?(existing.status)
errors.add(:base, "Already a maintainer of this set")
return false
end
if existing.status == 'blocked'
errors.add(:base, 'User has blocked you from inviting them to maintain this set')
return false
end
if existing.status == 'cooldown' && existing.created_at > 24.hours.ago
errors.add(:base, "User has been invited to maintain this set too recently")
return false
end
end
def ensure_set_public
unless post_set.is_public
errors.add(:post_set, 'must be public')
false
end
end
end
def maintained(user)
where(user_id: user.id, status: 'approved').joins(:post_set).where('post_set.is_public = true')
end
def self.active
where(status: 'approved')
end
def self.pending
where(status: 'pending')
end
include ValidaitonMethods
end

View File

@ -1,29 +1,29 @@
class TagTypeVersion < ApplicationRecord
belongs_to :tag
belongs_to_creator
module SearchMethods
def search(params = {})
q = super.includes(:creator, :tag)
if params[:tag].present?
tag = Tag.find_by_normalized_name(params[:tag])
q = q.where(tag_id: tag.id) if tag
end
if params[:user_id].present?
q = q.where('creator_id = ?', params[:user_id])
end
if params[:user_name].present?
name = User.find_by_name(params[:user_name])
q = q.where('creator_id = ? ', name.id) if id
end
q = q.order(id: :desc)
q
end
end
extend SearchMethods
end
class TagTypeVersion < ApplicationRecord
belongs_to :tag
belongs_to_creator
module SearchMethods
def search(params = {})
q = super.includes(:creator, :tag)
if params[:tag].present?
tag = Tag.find_by_normalized_name(params[:tag])
q = q.where(tag_id: tag.id) if tag
end
if params[:user_id].present?
q = q.where('creator_id = ?', params[:user_id])
end
if params[:user_name].present?
name = User.find_by_name(params[:user_name])
q = q.where('creator_id = ? ', name.id) if id
end
q = q.order(id: :desc)
q
end
end
extend SearchMethods
end

View File

@ -1,7 +1,7 @@
class UserStatus < ApplicationRecord
belongs_to :user
def self.for_user(user_id)
where("user_statuses.user_id = ?", user_id)
end
end
class UserStatus < ApplicationRecord
belongs_to :user
def self.for_user(user_id)
where("user_statuses.user_id = ?", user_id)
end
end

View File

@ -1,30 +1,30 @@
<table class="striped">
<thead>
<tr>
<th style="width: 200px">Created At</th>
<th>Code</th>
<th style="width: 100px">Version</th>
<th>Class Name</th>
<th>Message</th>
<th>Stacktrace</th>
</tr>
</thead>
<tbody>
<%- @exception_logs.each do |exception_log| %>
<tr style="cursor: click;">
<td><%= exception_log.created_at.strftime("%b %d, %Y %l:%M %p") %></td>
<td><%= exception_log.code %></td>
<td><%= exception_log.version %></td>
<td><%= exception_log.class_name %></td>
<td><%= exception_log.message %></td>
<td>
<%= link_to "View", admin_exception_path(exception_log) %>
</td>
</tr>
<% end %>
</tbody>
</table>
<div id="paginator">
<%= numbered_paginator(@exception_logs) %>
</div>
<table class="striped">
<thead>
<tr>
<th style="width: 200px">Created At</th>
<th>Code</th>
<th style="width: 100px">Version</th>
<th>Class Name</th>
<th>Message</th>
<th>Stacktrace</th>
</tr>
</thead>
<tbody>
<%- @exception_logs.each do |exception_log| %>
<tr style="cursor: click;">
<td><%= exception_log.created_at.strftime("%b %d, %Y %l:%M %p") %></td>
<td><%= exception_log.code %></td>
<td><%= exception_log.version %></td>
<td><%= exception_log.class_name %></td>
<td><%= exception_log.message %></td>
<td>
<%= link_to "View", admin_exception_path(exception_log) %>
</td>
</tr>
<% end %>
</tbody>
</table>
<div id="paginator">
<%= numbered_paginator(@exception_logs) %>
</div>

View File

@ -1,16 +1,16 @@
<div>
<div class="box-section">
<h3><%= @exception_log.class_name %></h3>
<p><%= @exception_log.message %></p>
<p>
Error Code: <%= @exception_log.code %><br/>
Created At: <%= @exception_log.created_at.strftime("%b %d, %Y %l:%M %p") %><br/>
Version: <%= @exception_log.version %><br/>
IP Address: <%= link_to_ip @exception_log.ip_addr %>
</p>
</div>
<strong>Extra Params:</strong>
<pre class="box-section"><%= JSON.pretty_generate(@exception_log.extra_params) %></pre>
<strong>Stacktrace:</strong>
<pre class="box-section"><%= @exception_log.trace %></pre>
</div>
<div>
<div class="box-section">
<h3><%= @exception_log.class_name %></h3>
<p><%= @exception_log.message %></p>
<p>
Error Code: <%= @exception_log.code %><br/>
Created At: <%= @exception_log.created_at.strftime("%b %d, %Y %l:%M %p") %><br/>
Version: <%= @exception_log.version %><br/>
IP Address: <%= link_to_ip @exception_log.ip_addr %>
</p>
</div>
<strong>Extra Params:</strong>
<pre class="box-section"><%= JSON.pretty_generate(@exception_log.extra_params) %></pre>
<strong>Stacktrace:</strong>
<pre class="box-section"><%= @exception_log.trace %></pre>
</div>

View File

@ -1,9 +1,9 @@
<div>
<h4>View User Blacklist</h4>
<div class='section' style='width:400px;'>
<%= form_tag({action: "update_blacklist"}, method: :post) do %>
<%= text_area "user", "blacklisted_tags", size: "60x20" %>
<%= submit_tag "Save", name: nil %>
<% end %>
</div>
</div>
<div>
<h4>View User Blacklist</h4>
<div class='section' style='width:400px;'>
<%= form_tag({action: "update_blacklist"}, method: :post) do %>
<%= text_area "user", "blacklisted_tags", size: "60x20" %>
<%= submit_tag "Save", name: nil %>
<% end %>
</div>
</div>

View File

@ -1,12 +1,12 @@
<div>
<h4>Reset Password</h4>
<% if @reset_key %>
<% if @user.email.blank? %>
<p>Password reset request created, but <%= @user.name %> has no email address associated with their account.<br>
<% else %>
<p>Password reset email successfully sent to <%= @user.name %> (<%= @user.email %>)<br>
<% end %>
Their password reset URL is: <a href='<%= edit_maintenance_user_password_reset_url(:host => Danbooru.config.hostname, :only_path => false, :key => @reset_key.key, :uid => @reset_key.user_id) %>'><%= edit_maintenance_user_password_reset_url(:host => Danbooru.config.hostname, :only_path => false, :key => @reset_key.key, :uid => @reset_key.user_id) %></a></p>
<% end %>
</div>
<div>
<h4>Reset Password</h4>
<% if @reset_key %>
<% if @user.email.blank? %>
<p>Password reset request created, but <%= @user.name %> has no email address associated with their account.<br>
<% else %>
<p>Password reset email successfully sent to <%= @user.name %> (<%= @user.email %>)<br>
<% end %>
Their password reset URL is: <a href='<%= edit_maintenance_user_password_reset_url(:host => Danbooru.config.hostname, :only_path => false, :key => @reset_key.key, :uid => @reset_key.user_id) %>'><%= edit_maintenance_user_password_reset_url(:host => Danbooru.config.hostname, :only_path => false, :key => @reset_key.key, :uid => @reset_key.user_id) %></a></p>
<% end %>
</div>

View File

@ -1,21 +1,21 @@
<div>
<h4>Reset Password</h4>
<div class='section' style='width:370px;'>
<%= form_tag(password_reset_admin_user_path(@user)) do %>
<table class='nomargin'>
<tr>
<td width="15%"><label class="block" for="user_name">Username</label></td>
<td width="85%"><%= text_field "user", "name", {value: @user ? @user.name : "", "data-autocomplete": 'user'} %></td>
</tr>
<tr>
<td><label class="block" for="admin_password">Admin Password</label></td>
<td><%= password_field "admin", "password", autocomplete: :off %></td>
</tr>
</table>
<%= submit_tag "Reset" %>
<% end %>
</div>
</div>
<div>
<h4>Reset Password</h4>
<div class='section' style='width:370px;'>
<%= form_tag(password_reset_admin_user_path(@user)) do %>
<table class='nomargin'>
<tr>
<td width="15%"><label class="block" for="user_name">Username</label></td>
<td width="85%"><%= text_field "user", "name", {value: @user ? @user.name : "", "data-autocomplete": 'user'} %></td>
</tr>
<tr>
<td><label class="block" for="admin_password">Admin Password</label></td>
<td><%= password_field "admin", "password", autocomplete: :off %></td>
</tr>
</table>
<%= submit_tag "Reset" %>
<% end %>
</div>
</div>

View File

@ -1,11 +1,11 @@
<div class='section' id='reply'>
<%= error_messages_for :blip %>
<%= simple_form_for(blip, :html => {:style => ("display: none;" if local_assigns[:hidden]), :class => "edit_blip"}) do |f| %>
<% if blip.new_record? %>
<%= f.hidden_field :response_to %>
<% end %>
<%= dtext_field "blip", "body", :value => blip.body, :input_id => "blip_body_for_#{blip.id}", :preview_id => "dtext-preview-for-#{blip.id}" %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "blip", "body", :input_id => "blip_body_for_#{blip.id}", :preview_id => "dtext-preview-for-#{blip.id}" %>
<% end %>
</div>
<div class='section' id='reply'>
<%= error_messages_for :blip %>
<%= simple_form_for(blip, :html => {:style => ("display: none;" if local_assigns[:hidden]), :class => "edit_blip"}) do |f| %>
<% if blip.new_record? %>
<%= f.hidden_field :response_to %>
<% end %>
<%= dtext_field "blip", "body", :value => blip.body, :input_id => "blip_body_for_#{blip.id}", :preview_id => "dtext-preview-for-#{blip.id}" %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "blip", "body", :input_id => "blip_body_for_#{blip.id}", :preview_id => "dtext-preview-for-#{blip.id}" %>
<% end %>
</div>

View File

@ -1,3 +1,3 @@
<%= form_tag(blips_path, :method => :get) do %>
<%= text_field "search", "body_matches", :id => "quick_search_body_matches", :placeholder => "Search blips" %>
<% end %>
<%= form_tag(blips_path, :method => :get) do %>
<%= text_field "search", "body_matches", :id => "quick_search_body_matches", :placeholder => "Search blips" %>
<% end %>

View File

@ -1,10 +1,10 @@
<div class="section" style="float: left; margin: 10px; padding: 5px; width: 97%;">
<% if blips.empty? %>
<p>No blips</p>
<% else %>
<% blips.each do |blip| %>
<% next unless blip.can_view?(current_user) %>
<div class="response-list"><%= render partial: "blip/blip", locals: {blip: blip} %></div>
<% end %>
<% end %>
</div>
<div class="section" style="float: left; margin: 10px; padding: 5px; width: 97%;">
<% if blips.empty? %>
<p>No blips</p>
<% else %>
<% blips.each do |blip| %>
<% next unless blip.can_view?(current_user) %>
<div class="response-list"><%= render partial: "blip/blip", locals: {blip: blip} %></div>
<% end %>
<% end %>
</div>

View File

@ -1,37 +1,37 @@
<div id="c-edit-history">
<div id="a-index">
<h1>Recent Edits</h1>
<table class='striped' style='width:100%;'>
<thead>
<tr>
<th></th>
<th>Type</th>
<th>Date</th>
<th>IP Address</th>
<th>Editor</th>
<th>Body</th>
<th>Subject</th>
</tr>
</thead>
<tbody>
<% @edit_history.each do |edit| %>
<tr id="edit-<%= edit.id %>">
<td><%= link_to "Show", action: "show", id: edit.versionable_id, type: edit.versionable_type %></td>
<td><%= edit.versionable_type %></td>
<td><%= edit.updated_at.strftime("%b %d, %Y %I:%M %p") %></td>
<td><%= link_to_ip edit.ip_addr %></td>
<td><%= link_to_user edit.user %></td>
<td><%= edit.body[0..30] %></td>
<td><%= edit.subject&[0..30] %></td>
</tr>
<% end %>
</tbody>
</table>
<div id="paginator">
<%= numbered_paginator(@edit_history) %>
</div>
</div>
</div>
<div id="c-edit-history">
<div id="a-index">
<h1>Recent Edits</h1>
<table class='striped' style='width:100%;'>
<thead>
<tr>
<th></th>
<th>Type</th>
<th>Date</th>
<th>IP Address</th>
<th>Editor</th>
<th>Body</th>
<th>Subject</th>
</tr>
</thead>
<tbody>
<% @edit_history.each do |edit| %>
<tr id="edit-<%= edit.id %>">
<td><%= link_to "Show", action: "show", id: edit.versionable_id, type: edit.versionable_type %></td>
<td><%= edit.versionable_type %></td>
<td><%= edit.updated_at.strftime("%b %d, %Y %I:%M %p") %></td>
<td><%= link_to_ip edit.ip_addr %></td>
<td><%= link_to_user edit.user %></td>
<td><%= edit.body[0..30] %></td>
<td><%= edit.subject&[0..30] %></td>
</tr>
<% end %>
</tbody>
</table>
<div id="paginator">
<%= numbered_paginator(@edit_history) %>
</div>
</div>
</div>

View File

@ -1,26 +1,26 @@
<div id="c-edit-history">
<div id="a-show">
<h1>Edits for <%= h params[:type] %> #<%= h params[:id] %></h1>
<div class="response-list" id="edit-history">
<% @edits.each_with_index do |edit, idx| %>
<div class="edit-item box-section">
<div class="author">
<h6><%= link_to_user edit.user %></h6>
<span class="date" title="<%= time_ago_in_words(edit.created_at) + " ago" %>"><%= edit.created_at.strftime("%b %d, %Y %I:%M %p") %></span>
<div><%= link_to_ip edit.ip_addr %></div>
</div>
<div class="content">
<div class="body">
<% if edit.version > 1 %>
<%= edit.diff(@edits[idx-1]) %>
<% else %>
<%= edit.body %>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>
<div id="c-edit-history">
<div id="a-show">
<h1>Edits for <%= h params[:type] %> #<%= h params[:id] %></h1>
<div class="response-list" id="edit-history">
<% @edits.each_with_index do |edit, idx| %>
<div class="edit-item box-section">
<div class="author">
<h6><%= link_to_user edit.user %></h6>
<span class="date" title="<%= time_ago_in_words(edit.created_at) + " ago" %>"><%= edit.created_at.strftime("%b %d, %Y %I:%M %p") %></span>
<div><%= link_to_ip edit.ip_addr %></div>
</div>
<div class="content">
<div class="body">
<% if edit.version > 1 %>
<%= edit.diff(@edits[idx-1]) %>
<% else %>
<%= edit.body %>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
<%= simple_form_for(:search, url: email_blacklists_path, method: :get, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :pattern, label: "Domain", hint: "Use * for wildcard", input_html: { value: params[:search][:domain]} %>
<%= f.input :reason, label: "Ban Reason", input_html: { value: params[:search][:reason] } %>
<%= f.input :order, collection: [["Recently created", "id"], ["Last updated", "updated_at"], ["Domain", "domain"], ["Reason", "reason"]], selected: params[:search][:order] %>
<%= f.submit "Search" %>
<% end %>
<%= simple_form_for(:search, url: email_blacklists_path, method: :get, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :pattern, label: "Domain", hint: "Use * for wildcard", input_html: { value: params[:search][:domain]} %>
<%= f.input :reason, label: "Ban Reason", input_html: { value: params[:search][:reason] } %>
<%= f.input :order, collection: [["Recently created", "id"], ["Last updated", "updated_at"], ["Domain", "domain"], ["Reason", "reason"]], selected: params[:search][:order] %>
<%= f.submit "Search" %>
<% end %>

View File

@ -1 +1 @@
<%= render "iqdb_queries/matches" %>
<%= render "iqdb_queries/matches" %>

View File

@ -1 +1 @@
<%= raw @results.map {|ip_addr, count| {ip_addr: ip_addr.to_s, count: count}}.to_json %>
<%= raw @results.map {|ip_addr, count| {ip_addr: ip_addr.to_s, count: count}}.to_json %>

View File

@ -1,10 +1,10 @@
<div class="box-section">
It is possible to search for IP address wildcards using CIDR notation, but only if searching for a single IP addr. You probably want '/24' at the end for IPv4 wildcards.
</div>
<%= simple_form_for(:search, method: :get, url: moderator_ip_addrs_path, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :user_id, label: "User IDs", input_html: { value: params[:search][:user_id] } %>
<%= f.input :user_name, label: "User Names", input_html: { value: params[:search][:user_name] } %>
<%= f.input :ip_addr, label: "IP Addresses", input_html: { value: params[:search][:ip_addr] } %>
<%= f.input :with_history, label: "With History", as: :boolean, input_html: { checked: params[:search][:with_history] } %>
<%= f.submit "Search" %>
<% end %>
<div class="box-section">
It is possible to search for IP address wildcards using CIDR notation, but only if searching for a single IP addr. You probably want '/24' at the end for IPv4 wildcards.
</div>
<%= simple_form_for(:search, method: :get, url: moderator_ip_addrs_path, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :user_id, label: "User IDs", input_html: { value: params[:search][:user_id] } %>
<%= f.input :user_name, label: "User Names", input_html: { value: params[:search][:user_name] } %>
<%= f.input :ip_addr, label: "IP Addresses", input_html: { value: params[:search][:ip_addr] } %>
<%= f.input :with_history, label: "With History", as: :boolean, input_html: { checked: params[:search][:with_history] } %>
<%= f.submit "Search" %>
<% end %>

View File

@ -1 +1 @@
<%= raw @results[:sums].to_json %>
<%= raw @results[:sums].to_json %>

View File

@ -1,16 +1,16 @@
<div id="c-post-report-reasons">
<div id="c-edit">
<h1>Edit Post Report Reason</h1>
<div>
<%= simple_form_for(@reason) do |f| %>
<%= f.input :reason, as: :string %>
<%= f.input :description, as: :string %>
<%= f.button :submit, "Edit" %>
<% end %>
</div>
</div>
</div>
<%= render partial: "secondary_links" %>
<div id="c-post-report-reasons">
<div id="c-edit">
<h1>Edit Post Report Reason</h1>
<div>
<%= simple_form_for(@reason) do |f| %>
<%= f.input :reason, as: :string %>
<%= f.input :description, as: :string %>
<%= f.button :submit, "Edit" %>
<% end %>
</div>
</div>
</div>
<%= render partial: "secondary_links" %>

View File

@ -1,12 +1,12 @@
<div class="simple_form">
<div class="input">
<label>Set Name</label>
<select id="add-to-set-id">
<option>Loading...</option>
</select>
</div>
<div class="input">
<button id="add-to-set-submit">Add</button>
</div>
</div>
<div class="simple_form">
<div class="input">
<label>Set Name</label>
<select id="add-to-set-id">
<option>Loading...</option>
</select>
</div>
<div class="input">
<button id="add-to-set-submit">Add</button>
</div>
</div>

View File

@ -1,7 +1,7 @@
<div id="anonymous-blacklist-dialog" title="Anonymous Blacklist" style="display: none;">
<h4>Tag Blacklist</h4>
<textarea id="anonymous-blacklist-edit" rows="8" cols="30"></textarea>
<input type="button" value="Save" id="anonymous-blacklist-save"/>
<input type="button" value="Cancel" id="anonymous-blacklist-cancel" /><br />
<p>Additional help about the blacklist can be found <%= link_to "here", help_page_path(id: "blacklist") %></p>
</div>
<div id="anonymous-blacklist-dialog" title="Anonymous Blacklist" style="display: none;">
<h4>Tag Blacklist</h4>
<textarea id="anonymous-blacklist-edit" rows="8" cols="30"></textarea>
<input type="button" value="Save" id="anonymous-blacklist-save"/>
<input type="button" value="Cancel" id="anonymous-blacklist-cancel" /><br />
<p>Additional help about the blacklist can be found <%= link_to "here", help_page_path(id: "blacklist") %></p>
</div>

View File

@ -1,20 +1,20 @@
<div class="guest-warning" style="display: none;">
<div class="guest-warning-dialog">
<h1 class="dialog-header">Over 18?</h1>
<div class="dialog-content">
<p>
You must be over the age of 18 and agree
to <%= link_to "the terms of service", terms_of_service_path, target: "_blank" %> to access this page.
</p>
<p>
By default a limited blacklist has been applied removing content that is commonly objected to. You may remove
items
from this blacklist by using the blacklist menu item.
</p>
</div>
<div class="dialog-footer">
<button id="guest-warning-accept">I agree and am over 18</button>
<button id="guest-warning-decline">I do not agree, or am not over 18</button>
</div>
</div>
</div>
<div class="guest-warning" style="display: none;">
<div class="guest-warning-dialog">
<h1 class="dialog-header">Over 18?</h1>
<div class="dialog-content">
<p>
You must be over the age of 18 and agree
to <%= link_to "the terms of service", terms_of_service_path, target: "_blank" %> to access this page.
</p>
<p>
By default a limited blacklist has been applied removing content that is commonly objected to. You may remove
items
from this blacklist by using the blacklist menu item.
</p>
</div>
<div class="dialog-footer">
<button id="guest-warning-accept">I agree and am over 18</button>
<button id="guest-warning-decline">I do not agree, or am not over 18</button>
</div>
</div>
</div>

View File

@ -0,0 +1 @@

View File

@ -1,2 +1,2 @@
<h1>Too Many Requests</h1>
<p>Please rate limit yourself</p>
<p>Please rate limit yourself</p>

View File

@ -1,40 +1,40 @@
<div id="c-tag-type-version">
<div id="a-index">
<%= render partial: 'search' %>
<div>
<table class="striped">
<thead>
<tr>
<th style="width:70px;">Tag</th>
<th style="width:60px;">Date</th>
<th style="width:220px;">User</th>
<th style="width:55px;">Old Type</th>
<th style="width:70px;">New type</th>
<th style="width:200px;">Locked</th>
</tr>
</thead>
<tbody>
<% @tag_versions.each do |change| %>
<tr id="r<%= change.id %>">
<td><%= link_to change.tag.name, edit_tag_path(change.tag) %></td>
<td>
<span title='<%= change.created_at.strftime("%b %d, %Y %I:%M %p") %>'><%= change.created_at.strftime("%b %d") %></span>
</td>
<td><%= link_to_user change.creator %></td>
<td><a class="<%= "tag-type-#{change.old_type}" %>"><%= Tag.category_for_value(change.old_type) %></a></td>
<td><a class="<%= "tag-type-#{change.new_type}" %>"><%= Tag.category_for_value(change.new_type) %></a></td>
<td><%= change.is_locked %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="paginator">
<%= sequential_paginator(@tag_versions) %>
</div>
</div>
</div>
<div id="c-tag-type-version">
<div id="a-index">
<%= render partial: 'search' %>
<div>
<table class="striped">
<thead>
<tr>
<th style="width:70px;">Tag</th>
<th style="width:60px;">Date</th>
<th style="width:220px;">User</th>
<th style="width:55px;">Old Type</th>
<th style="width:70px;">New type</th>
<th style="width:200px;">Locked</th>
</tr>
</thead>
<tbody>
<% @tag_versions.each do |change| %>
<tr id="r<%= change.id %>">
<td><%= link_to change.tag.name, edit_tag_path(change.tag) %></td>
<td>
<span title='<%= change.created_at.strftime("%b %d, %Y %I:%M %p") %>'><%= change.created_at.strftime("%b %d") %></span>
</td>
<td><%= link_to_user change.creator %></td>
<td><a class="<%= "tag-type-#{change.old_type}" %>"><%= Tag.category_for_value(change.old_type) %></a></td>
<td><a class="<%= "tag-type-#{change.new_type}" %>"><%= Tag.category_for_value(change.new_type) %></a></td>
<td><%= change.is_locked %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="paginator">
<%= sequential_paginator(@tag_versions) %>
</div>
</div>
</div>

View File

@ -1,11 +1,11 @@
<% content_for(:secondary_links) do %>
<menu>
<%= subnav_link_to 'List', tickets_path %>
<% unless CurrentUser.is_anonymous? %>
<%= subnav_link_to 'Mine', tickets_path(search: {creator_id: CurrentUser.id}) %>
<% end %>
<% if CurrentUser.is_admin? %>
<%= subnav_link_to 'Claimed', tickets_path(search: {claimant_id: CurrentUser.id}) %>
<% end %>
</menu>
<% end %>
<% content_for(:secondary_links) do %>
<menu>
<%= subnav_link_to 'List', tickets_path %>
<% unless CurrentUser.is_anonymous? %>
<%= subnav_link_to 'Mine', tickets_path(search: {creator_id: CurrentUser.id}) %>
<% end %>
<% if CurrentUser.is_admin? %>
<%= subnav_link_to 'Claimed', tickets_path(search: {claimant_id: CurrentUser.id}) %>
<% end %>
</menu>
<% end %>

View File

@ -1,66 +1,66 @@
<div id="c-tickets">
<div id="a-new">
<%= simple_form_for(@ticket) do |f| %>
<% @found_item = true %>
<% if params[:type].nil? %>
<% @found_item = false %>
<div class='section' style='width:80em;'>
To submit a ticket about a problematic comment, click "Report" on the comment itself.<br/>
To submit a ticket about a problematic forum post, click "Report" on the post itself.<br/>
To submit a ticket about a problematic pool, click "Report" on the pool page itself.<br/>
To submit a ticket about a problematic set, click "Report" on the set page itself.<br/>
To submit a ticket about a problematic user, click "Report" on the user's profile page.<br/>
To submit a ticket about a problematic private message, click "Report PM" above the PM itself.<br/>
To submit a username request, click "Request Username Change" on <a href='/user/home'>the user home page</a>.<br/>
</div>
<% elsif CurrentUser.is_anonymous? %>
<% @found_item = false %>
<div class='section' style='width:80em;'>
You must be logged in to submit a ticket. Please <a href='/user/login'>log in</a> and try again.
</div>
<% elsif @ticket.type_valid %>
<%= render partial: "tickets/new_types/#{@ticket.qtype}" %>
<% else %>
<% @found_item = false %>
<div class='section' style='width:80em;'>
Hmm, it seems you tried to report something that doesn't make sense.
</div>
<% end %>
<% if @found_item %>
<%= f.hidden_field :disp_id %>
<%= f.hidden_field :qtype %>
<div class='section' style='width:80em;'>
<label for="ticket_reason">
<% if params[:type] == "namechange" %>
Desired username
<% elsif params[:type] == "post" %>
Additional details.
<% else %>
Reason for complaint
<% end %>
</label><br/>
<% if params[:type] == "namechange" %>
<p class='nomargin'>Note: Multiple name change requests made within a short period of time may not be
honored</p>
<%= f.input :reason, as: :text, maxlength: 20 %><br/>
<% else %>
<p class='nomargin'>Note: Abuse of this system will lead to disciplinary action</p>
<%= dtext_field "ticket", "reason", :value => @ticket.reason, :input_id => "ticket_reason", :preview_id => "dtext-preview-for-ticket-reason" %>
<% end %>
</div>
<% if params[:type] == "namechange" %>
<%= submit_tag "Submit Request" %>
<% else %>
<%= submit_tag "Submit Complaint" %> <%= dtext_preview_button "ticket", "reason", :input_id => "ticket_reason", :preview_id => "dtext-preview-for-ticket-reason" %>
<% end %>
<% end %>
<% end %>
</div>
</div>
<% render partial: 'secondary_links' %>
<div id="c-tickets">
<div id="a-new">
<%= simple_form_for(@ticket) do |f| %>
<% @found_item = true %>
<% if params[:type].nil? %>
<% @found_item = false %>
<div class='section' style='width:80em;'>
To submit a ticket about a problematic comment, click "Report" on the comment itself.<br/>
To submit a ticket about a problematic forum post, click "Report" on the post itself.<br/>
To submit a ticket about a problematic pool, click "Report" on the pool page itself.<br/>
To submit a ticket about a problematic set, click "Report" on the set page itself.<br/>
To submit a ticket about a problematic user, click "Report" on the user's profile page.<br/>
To submit a ticket about a problematic private message, click "Report PM" above the PM itself.<br/>
To submit a username request, click "Request Username Change" on <a href='/user/home'>the user home page</a>.<br/>
</div>
<% elsif CurrentUser.is_anonymous? %>
<% @found_item = false %>
<div class='section' style='width:80em;'>
You must be logged in to submit a ticket. Please <a href='/user/login'>log in</a> and try again.
</div>
<% elsif @ticket.type_valid %>
<%= render partial: "tickets/new_types/#{@ticket.qtype}" %>
<% else %>
<% @found_item = false %>
<div class='section' style='width:80em;'>
Hmm, it seems you tried to report something that doesn't make sense.
</div>
<% end %>
<% if @found_item %>
<%= f.hidden_field :disp_id %>
<%= f.hidden_field :qtype %>
<div class='section' style='width:80em;'>
<label for="ticket_reason">
<% if params[:type] == "namechange" %>
Desired username
<% elsif params[:type] == "post" %>
Additional details.
<% else %>
Reason for complaint
<% end %>
</label><br/>
<% if params[:type] == "namechange" %>
<p class='nomargin'>Note: Multiple name change requests made within a short period of time may not be
honored</p>
<%= f.input :reason, as: :text, maxlength: 20 %><br/>
<% else %>
<p class='nomargin'>Note: Abuse of this system will lead to disciplinary action</p>
<%= dtext_field "ticket", "reason", :value => @ticket.reason, :input_id => "ticket_reason", :preview_id => "dtext-preview-for-ticket-reason" %>
<% end %>
</div>
<% if params[:type] == "namechange" %>
<%= submit_tag "Submit Request" %>
<% else %>
<%= submit_tag "Submit Complaint" %> <%= dtext_preview_button "ticket", "reason", :input_id => "ticket_reason", :preview_id => "dtext-preview-for-ticket-reason" %>
<% end %>
<% end %>
<% end %>
</div>
</div>
<% render partial: 'secondary_links' %>

View File

@ -1,12 +1,12 @@
<% unless @ticket.blip %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That blip does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<h4>You are reporting the following blip:</h4>
<div class="author"><%= link_to_user(@ticket.blip.creator) %></div>
<span class="date" title="Posted on <%= @ticket.blip.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@ticket.blip.created_at) %> ago</span>
<br /><br />
<%= format_text(@ticket.blip.body) %>
</div>
<% end %>
<% unless @ticket.blip %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That blip does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<h4>You are reporting the following blip:</h4>
<div class="author"><%= link_to_user(@ticket.blip.creator) %></div>
<span class="date" title="Posted on <%= @ticket.blip.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@ticket.blip.created_at) %> ago</span>
<br /><br />
<%= format_text(@ticket.blip.body) %>
</div>
<% end %>

View File

@ -1,13 +1,13 @@
<% unless @ticket.comment %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That comment does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @comment = @ticket.comment %>
<h4>You are reporting the following comment:</h4>
<div class="author"><%= link_to_user @comment.creator %></div>
<span class="date" title="Posted on <%= @comment.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@comment.created_at) %> ago</span>
<br /><br />
<%= format_text(@comment.body) %>
</div>
<% end %>
<% unless @ticket.comment %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That comment does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @comment = @ticket.comment %>
<h4>You are reporting the following comment:</h4>
<div class="author"><%= link_to_user @comment.creator %></div>
<span class="date" title="Posted on <%= @comment.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@comment.created_at) %> ago</span>
<br /><br />
<%= format_text(@comment.body) %>
</div>
<% end %>

View File

@ -1,13 +1,13 @@
<% unless @ticket.dmail && @ticket.dmail.visible_to?(CurrentUser.user) %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That message does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @dmail = @ticket.dmail %>
<h4>You are reporting the following private message:</h4>
<div class='author'><%= link_to_user @dmail.from %></div>
<span class="date" title="Sent on <%= @dmail.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@dmail.created_at) %>
ago</span>
<%= format_text(@dmail.body) %>
</div>
<% end %>
<% unless @ticket.dmail && @ticket.dmail.visible_to?(CurrentUser.user) %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That message does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @dmail = @ticket.dmail %>
<h4>You are reporting the following private message:</h4>
<div class='author'><%= link_to_user @dmail.from %></div>
<span class="date" title="Sent on <%= @dmail.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@dmail.created_at) %>
ago</span>
<%= format_text(@dmail.body) %>
</div>
<% end %>

View File

@ -1,12 +1,12 @@
<% unless @ticket.forum %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That forum post does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @forum = @ticket.forum %>
<h4>You are reporting the following forum post:</h4>
<div class='author'><%= link_to_user(@forum.creator) %></div>
<span class="date" title="Posted on <%= @forum.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@forum.created_at) %> ago</span>
<%= format_text(@forum.body) %>
</div>
<% end %>
<% unless @ticket.forum %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That forum post does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @forum = @ticket.forum %>
<h4>You are reporting the following forum post:</h4>
<div class='author'><%= link_to_user(@forum.creator) %></div>
<span class="date" title="Posted on <%= @forum.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@forum.created_at) %> ago</span>
<%= format_text(@forum.body) %>
</div>
<% end %>

View File

@ -1,18 +1,18 @@
<% unless (params[:disp_id].to_i == current_user.id) %>
<% @found_item = false %>
<div class='section' style='width:80em;'>You can only change your own username.</div>
<% else %>
<div class='section' style='width:80em;'>
<p>You are requesting to change your username.</p>
<p>Usernames may contain:
<ul>
<li>Non-accented letters (<b>A-Z</b>)</li>
<li>Numbers (<b>0-9</b>)</li>
<li>The following symbols: <b>-_~'</b></li>
</ul>
<p>The name change is not automated, but must be approved by an Administrator.
Requests are usually handled within 24 hours, but it may take up to 3 days to process.
Once the name change has been approved your old username is able to used by other users.
Please ensure that you are willing to risk losing your name!</p>
</div>
<% end %>
<% unless (params[:disp_id].to_i == current_user.id) %>
<% @found_item = false %>
<div class='section' style='width:80em;'>You can only change your own username.</div>
<% else %>
<div class='section' style='width:80em;'>
<p>You are requesting to change your username.</p>
<p>Usernames may contain:
<ul>
<li>Non-accented letters (<b>A-Z</b>)</li>
<li>Numbers (<b>0-9</b>)</li>
<li>The following symbols: <b>-_~'</b></li>
</ul>
<p>The name change is not automated, but must be approved by an Administrator.
Requests are usually handled within 24 hours, but it may take up to 3 days to process.
Once the name change has been approved your old username is able to used by other users.
Please ensure that you are willing to risk losing your name!</p>
</div>
<% end %>

View File

@ -1,14 +1,14 @@
<% unless @ticket.pool %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That pool does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @pool = @ticket.pool %>
<h4>You are reporting the following pool:</h4>
<div class='page'><%= fast_link_to(@pool.name, controller: "pools", id: @pool.id) %></div>
<div class='author'><%= link_to_user(@pool.creator) %></div>
<span class="date" title="Created on <%= @pool.created_at.strftime("%b %d, %Y %I:%M %p") %>">
<%= time_ago_in_words(@pool.created_at) %>ago
</span>
</div>
<% end %>
<% unless @ticket.pool %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That pool does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @pool = @ticket.pool %>
<h4>You are reporting the following pool:</h4>
<div class='page'><%= fast_link_to(@pool.name, controller: "pools", id: @pool.id) %></div>
<div class='author'><%= link_to_user(@pool.creator) %></div>
<span class="date" title="Created on <%= @pool.created_at.strftime("%b %d, %Y %I:%M %p") %>">
<%= time_ago_in_words(@pool.created_at) %>ago
</span>
</div>
<% end %>

View File

@ -1,12 +1,12 @@
<% unless @ticket.set %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That set does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @set = @ticket.set %>
<h4>You are reporting the following set:</h4>
<div class='page'><%= fast_link_to(@set.name, controller: "set", action: "show", id: @set.id) %></div>
<div class='author'><%= link_to_user(@set.creator) %></div>
<span class="date" title="Created on <%= @set.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@set.created_at) %> ago</span>
</div>
<% end %>
<% unless @ticket.set %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That set does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @set = @ticket.set %>
<h4>You are reporting the following set:</h4>
<div class='page'><%= fast_link_to(@set.name, controller: "set", action: "show", id: @set.id) %></div>
<div class='author'><%= link_to_user(@set.creator) %></div>
<span class="date" title="Created on <%= @set.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@set.created_at) %> ago</span>
</div>
<% end %>

View File

@ -1,8 +1,8 @@
<% unless @ticket.accused %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That user does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
You are reporting/commending <%= link_to_user(@ticket.accused) %>.
</div>
<% end %>
<% unless @ticket.accused %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That user does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
You are reporting/commending <%= link_to_user(@ticket.accused) %>.
</div>
<% end %>

View File

@ -1,12 +1,12 @@
<% unless @ticket.wiki %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That wiki page does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @wiki = @ticket.wiki %>
<h4>You are reporting the following wiki page:</h4>
<div class='page'><%= link_to_wiki @wiki.title %></div>
<span class="date" title="Posted on <%= @wiki.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@wiki.created_at) %> ago</span>
<%= format_text(@wiki.body) %>
</div>
<% end %>
<% unless @ticket.wiki %>
<% @found_item = false %>
<div class='section' style='width:80em;'>That wiki page does not exist.</div>
<% else %>
<div class='section' style='width:80em;'>
<% @wiki = @ticket.wiki %>
<h4>You are reporting the following wiki page:</h4>
<div class='page'><%= link_to_wiki @wiki.title %></div>
<span class="date" title="Posted on <%= @wiki.created_at.strftime("%b %d, %Y %I:%M %p") %>"><%= time_ago_in_words(@wiki.created_at) %> ago</span>
<%= format_text(@wiki.body) %>
</div>
<% end %>

View File

@ -1,13 +1,13 @@
<% if @ticket.blip %>
<tr>
<td><span class='title'>Reported Blip</span></td>
<td>
<%= link_to "Blip by #{@ticket.blip.creator_name}", blip_path(@ticket.blip) %>
</td>
</tr>
<% else %>
<tr>
<td><span class='title'>Reported Blip</span></td>
<td><span class='redtext'>Blip has been deleted</span></td>
</tr>
<% end %>
<% if @ticket.blip %>
<tr>
<td><span class='title'>Reported Blip</span></td>
<td>
<%= link_to "Blip by #{@ticket.blip.creator_name}", blip_path(@ticket.blip) %>
</td>
</tr>
<% else %>
<tr>
<td><span class='title'>Reported Blip</span></td>
<td><span class='redtext'>Blip has been deleted</span></td>
</tr>
<% end %>

View File

@ -1,14 +1,14 @@
<% if @ticket.comment %>
<tr>
<td><span class='title'>Reported Comment</span></td>
<td>
<%= fast_link_to("Comment by #{@ticket.comment.creator_name}", comment_path(@ticket.comment)) %> on
<%= fast_link_to("post ##{@ticket.comment.post_id}", post_path(@ticket.comment.post_id)) %>
</td>
</tr>
<% else %>
<tr>
<td><span class='title'>Reported Comment</span></td>
<td><span class='redtext'>Comment has been deleted</span></td>
</tr>
<% end %>
<% if @ticket.comment %>
<tr>
<td><span class='title'>Reported Comment</span></td>
<td>
<%= fast_link_to("Comment by #{@ticket.comment.creator_name}", comment_path(@ticket.comment)) %> on
<%= fast_link_to("post ##{@ticket.comment.post_id}", post_path(@ticket.comment.post_id)) %>
</td>
</tr>
<% else %>
<tr>
<td><span class='title'>Reported Comment</span></td>
<td><span class='redtext'>Comment has been deleted</span></td>
</tr>
<% end %>

View File

@ -1,13 +1,13 @@
<tr>
<td><span class='title'>Reported Message</span></td>
<td>
<% if @ticket.can_see_details?(CurrentUser) %>
<% @dmail = @ticket.dmail %>
<%= link_to "Message", dmail_path(@ticket.dmail) %>
sent from <%= link_to_user @ticket.dmail.from %> to
<%= link_to_user @ticket.dmail.to %>
<% else %>
<span style="cursor:help;" class="redtext" title="Due to privacy concerns, this information is confidential">Confidential</span>
<% end %>
</td>
</tr>
<tr>
<td><span class='title'>Reported Message</span></td>
<td>
<% if @ticket.can_see_details?(CurrentUser) %>
<% @dmail = @ticket.dmail %>
<%= link_to "Message", dmail_path(@ticket.dmail) %>
sent from <%= link_to_user @ticket.dmail.from %> to
<%= link_to_user @ticket.dmail.to %>
<% else %>
<span style="cursor:help;" class="redtext" title="Due to privacy concerns, this information is confidential">Confidential</span>
<% end %>
</td>
</tr>

View File

@ -1,6 +1,6 @@
<% if @ticket.pool %>
<tr>
<td><span class='title'>Reported Pool</span></td>
<td><%= fast_link_to(@ticket.pool.name, controller: "pools", id: @ticket.pool.id) %></td>
</tr>
<% end %>
<% if @ticket.pool %>
<tr>
<td><span class='title'>Reported Pool</span></td>
<td><%= fast_link_to(@ticket.pool.name, controller: "pools", id: @ticket.pool.id) %></td>
</tr>
<% end %>

View File

@ -1,6 +1,6 @@
<% if (@set = PostSet.find_by_id(@ticket.disp_id)) %>
<tr>
<td><span class='title'>Reported Set</span></td>
<td><%= fast_link_to(@set.name, controller: "set", action: "show", id: @set.id) %></td>
</tr>
<% end %>
<% if (@set = PostSet.find_by_id(@ticket.disp_id)) %>
<tr>
<td><span class='title'>Reported Set</span></td>
<td><%= fast_link_to(@set.name, controller: "set", action: "show", id: @set.id) %></td>
</tr>
<% end %>

View File

@ -1,8 +1,8 @@
<tr>
<td><span class='title'>Reported User</span></td>
<% if @ticket.can_see_details?(CurrentUser.user) %>
<td><%= link_to_user(@ticket.accused) %></td>
<% else %>
<td><span style="cursor:help;" class="redtext" title="Due to privacy concerns, this information is confidential">Confidential</span></td>
<% end %>
</tr>
<tr>
<td><span class='title'>Reported User</span></td>
<% if @ticket.can_see_details?(CurrentUser.user) %>
<td><%= link_to_user(@ticket.accused) %></td>
<% else %>
<td><span style="cursor:help;" class="redtext" title="Due to privacy concerns, this information is confidential">Confidential</span></td>
<% end %>
</tr>

View File

@ -1,7 +1,7 @@
<%= simple_form_for(:search, url: upload_whitelists_path, method: :get, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :pattern, label: "Pattern", hint: "Use * for wildcard", input_html: { value: params[:search][:pattern]} %>
<%= f.input :note, label: "Note", as: "string", input_html: { value: params[:search][:note] } %>
<%= f.input :reason, label: "Ban Reason", input_html: { value: params[:search][:reason] } %>
<%= f.input :order, collection: [["Recently created", "id"], ["Last updated", "updated_at"], ["Pattern", "pattern"], ["Note", "note"]], selected: params[:search][:order] %>
<%= f.submit "Search" %>
<% end %>
<%= simple_form_for(:search, url: upload_whitelists_path, method: :get, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :pattern, label: "Pattern", hint: "Use * for wildcard", input_html: { value: params[:search][:pattern]} %>
<%= f.input :note, label: "Note", as: "string", input_html: { value: params[:search][:note] } %>
<%= f.input :reason, label: "Ban Reason", input_html: { value: params[:search][:reason] } %>
<%= f.input :order, collection: [["Recently created", "id"], ["Last updated", "updated_at"], ["Pattern", "pattern"], ["Note", "note"]], selected: params[:search][:order] %>
<%= f.submit "Search" %>
<% end %>

View File

@ -1,22 +1,22 @@
<div id="c-upload-whitelist">
<div id="a-edit">
<h1>Upload Whitelist</h1>
<%= error_messages_for "whitelist" %>
<%= simple_form_for(@whitelist) do |f| %>
<%= f.input :pattern, label: "Pattern", as: :string %>
<%= f.input :note, label: "Note", as: :string %>
<%= f.input :allowed, label: "Upload Allowed", as: :boolean %>
<%= f.input :reason, label: "Ban Reason", as: :string %>
<%= f.input :hidden, label: "Hidden From Users", as: :boolean %>
<%= f.button :submit, "Save" %>
<% end %>
</div>
</div>
<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Edit Upload Whitelist - <%= Danbooru.config.app_name %>
<% end %>
<div id="c-upload-whitelist">
<div id="a-edit">
<h1>Upload Whitelist</h1>
<%= error_messages_for "whitelist" %>
<%= simple_form_for(@whitelist) do |f| %>
<%= f.input :pattern, label: "Pattern", as: :string %>
<%= f.input :note, label: "Note", as: :string %>
<%= f.input :allowed, label: "Upload Allowed", as: :boolean %>
<%= f.input :reason, label: "Ban Reason", as: :string %>
<%= f.input :hidden, label: "Hidden From Users", as: :boolean %>
<%= f.button :submit, "Save" %>
<% end %>
</div>
</div>
<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Edit Upload Whitelist - <%= Danbooru.config.app_name %>
<% end %>

View File

@ -1,44 +1,44 @@
<h2>Upload Limit</h2>
<div style="margin-bottom: 1em;">
<% unless CurrentUser.can_upload_free? %>
<p>You can currently upload <strong><%= CurrentUser.upload_limit %></strong> posts. This limit is based on the following formula:</p>
<ul>
<li>Approved: <%= @approved_count %></li>
<li>Deleted: <%= @deleted_count %></li>
<li>Pending/Flagged: <%= @pending_count %></li>
<li>Formula: <%= @presenter.upload_limit(self)%></li>
</ul>
<p>
This means you are able to upload a maximum of <span style='font-weight:bold'><%= CurrentUser.upload_limit %></span> unapproved posts at a time.
Once a moderator approves some of your posts, you can upload more.<br />
You cannot upload anything within the first week of registration.<br />
If your limit ends up negative due to a large number of deleted posts, please contact <%= Danbooru.config.contact_email %> to have it corrected.
</p>
<% end %>
<p>
<% unless CurrentUser.can_upload_free? %>
In addition to this, you are limited to 30 uploads per hour.
You also may not upload if you have no remaining tag edits per hour.
<% else %>
You are limited to 30 uploads per hour.
<% end %>
</p>
<ul>
<li>Remaining hourly uploads: <%= CurrentUser.hourly_upload_limit %></li>
<% if !CurrentUser.can_upload_free? %><li>Remaining hourly tag edits: <%= CurrentUser.post_edit_limit %></li><% end %>
</ul>
<% unless CurrentUser.can_upload_free? %>
<p>
If either of these limits reaches zero, you may not upload until some time has passed and these limits increase automatically.
</p>
<% else %>
<p>
If this limit reaches zero, you may not upload until some time has passed and the limit increases automatically.
</p>
<% end %>
</div>
<h2>Upload Limit</h2>
<div style="margin-bottom: 1em;">
<% unless CurrentUser.can_upload_free? %>
<p>You can currently upload <strong><%= CurrentUser.upload_limit %></strong> posts. This limit is based on the following formula:</p>
<ul>
<li>Approved: <%= @approved_count %></li>
<li>Deleted: <%= @deleted_count %></li>
<li>Pending/Flagged: <%= @pending_count %></li>
<li>Formula: <%= @presenter.upload_limit(self)%></li>
</ul>
<p>
This means you are able to upload a maximum of <span style='font-weight:bold'><%= CurrentUser.upload_limit %></span> unapproved posts at a time.
Once a moderator approves some of your posts, you can upload more.<br />
You cannot upload anything within the first week of registration.<br />
If your limit ends up negative due to a large number of deleted posts, please contact <%= Danbooru.config.contact_email %> to have it corrected.
</p>
<% end %>
<p>
<% unless CurrentUser.can_upload_free? %>
In addition to this, you are limited to 30 uploads per hour.
You also may not upload if you have no remaining tag edits per hour.
<% else %>
You are limited to 30 uploads per hour.
<% end %>
</p>
<ul>
<li>Remaining hourly uploads: <%= CurrentUser.hourly_upload_limit %></li>
<% if !CurrentUser.can_upload_free? %><li>Remaining hourly tag edits: <%= CurrentUser.post_edit_limit %></li><% end %>
</ul>
<% unless CurrentUser.can_upload_free? %>
<p>
If either of these limits reaches zero, you may not upload until some time has passed and these limits increase automatically.
</p>
<% else %>
<p>
If this limit reaches zero, you may not upload until some time has passed and the limit increases automatically.
</p>
<% end %>
</div>

View File

@ -6,4 +6,4 @@ server "saitou", :roles => %w(web app)
server "oogaki", :roles => %w(worker)
set :linked_files, fetch(:linked_files, []).push(".env.production")
set :rbenv_path, "/home/danbooru/.rbenv"
set :rbenv_path, "/home/danbooru/.rbenv"

View File

@ -67,4 +67,4 @@ services:
- db
- memcached
- archives
- redis
- redis

View File

@ -46,4 +46,4 @@ RUN yarn install
COPY script/install/database.yml.templ /app/config/database.yml
COPY script/install/danbooru_local_config.rb.templ /app/config/danbooru_local_config.rb
EXPOSE 3000
CMD sleep 1d
CMD sleep 1d

View File

@ -1 +1 @@
Elasticsearch::Model.client = Elasticsearch::Client.new host: Danbooru.config.elasticsearch_host
Elasticsearch::Model.client = Elasticsearch::Client.new host: Danbooru.config.elasticsearch_host

View File

@ -1,3 +1,3 @@
Mailgun.configure do |config|
config.api_key = Danbooru.config.mailgun_api_key
end
Mailgun.configure do |config|
config.api_key = Danbooru.config.mailgun_api_key
end

View File

@ -61,4 +61,4 @@ if Rails.env.test?
alias_method :fetch_without_retry, :fetch
alias_method :fetch, :fetch_with_retry
end
end
end

View File

@ -1 +1 @@
ActiveModelSerializers.config.adapter = :json
ActiveModelSerializers.config.adapter = :json

View File

@ -1,9 +1,9 @@
require 'sidekiq'
Sidekiq.configure_server do |config|
config.redis = { url: Danbooru.config.redis_url }
end
Sidekiq.configure_client do |config|
config.redis = { url: Danbooru.config.redis_url }
end
require 'sidekiq'
Sidekiq.configure_server do |config|
config.redis = { url: Danbooru.config.redis_url }
end
Sidekiq.configure_client do |config|
config.redis = { url: Danbooru.config.redis_url }
end

View File

@ -23,4 +23,4 @@ production:
staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

View File

@ -44,4 +44,4 @@ after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
end

View File

@ -1,446 +1,446 @@
images:
- tags: zoodystopia 2016 anthro bandage black_nose brown_fur canine clothed clothing
collar disney fox fur gloves_(marking) green_eyes looking_at_viewer male mammal
markings multicolored_fur nick_wilde open_shirt orange_fur pantssad shirt shock_collar
simple_background solo standing turningtides_(artist) white_background zootopia
url: https://static1.e621.net/data/87/8f/878f64f8df553ce09218bc9b1083b4e3.png
- tags: 5:4 2016 3_toes anthro barefoot canine claws clothed clothing cuddling disney
duo fabienne_growley female flat_chested fox green_eyes ipoke judy_hopps lagomorph
male mammal nick_wilde peter_moosebridge phone purple_eyes rabbit sitting smile
sofa soles television toes zootopia
url: https://static1.e621.net/data/62/f1/62f197461e755a7d4bd5884dc8ff20d6.jpg
- tags: begging begging_pose blue_fur blue_tail canine chest_tuft dipstick_tail facial_markings
fan_character feral feralized fluffy fur looking_away male mammal markings mask_(marking)
multicolored_fur multicolored_tail nintendo pokémon pokémon_(species) portrait red_eyes
riolu simple_background smile solo tuft two_tone_fur two_tone_tail umpherio_(umpherio)
video_games white_background white_fur white_tail xnirox
url: https://static1.e621.net/data/97/38/973887346d669d97c7a75b7324855773.png
- tags: felid pantherine 2017 armor big_breasts black_lips blue_eyes blue_hair bodysuit
breasts clothed clothing f-r95 female fingerless_gloves fluffy fluffy_tail gloves
hair inner_ear_fluff inside knee_pads long_tail looking_away looking_outside mammal
pink_noseshoulder_pads sitting skinsuit snow_leopard solo space spots tight_clothing
toeless_footwear yuna_snowleopard
url: https://static1.e621.net/data/34/7f/347fec14942b176b074c1cad64c31ad2.png
- tags: back_muscles 2015 anthro ass_up bed bedroom black_fur black_stripes book bookshelf
butt crawling feline fireplace fur green_eyes hax_(artist) inside kenket lofi
lying male mammal morning multicolored_fur nude on_floor on_front one_eye_closed
orange_fur painting pawpads platerug shaded solo striped_body stripes table tiger
vase white_fur window
url: https://static1.e621.net/data/sample/6f/f4/6ff406e64fe870f43512d863a8fd119b.jpg
- tags: pink_eyes 2018 anthro canine clothed clothing cookie digital_media_(artwork)
dog female food fur hair looking_at_viewer mammal nana_(fadey) open_mouthsmile
solo standing tofu93
url: https://static1.e621.net/data/sample/0f/01/0f01bc5401835aa1a082b19e83a0e956.jpg
- tags: 2013 anthro beverage blue_fur blue_hair borny_(character) canine clothing
coffee digital_media_(artwork) food fox fur green_eyes hair hoodie male mammal
open_mouth phonesolo wolfy-nail
url: https://static1.e621.net/data/sample/ac/9f/ac9f231b988d4b6f43b66e89e1d5578e.jpg
- tags: clothed detailed_background fully_clothed holding_object menacing outside
standing yellow_sclera 2015 anthro cheetah clothing feline female flashlight gun
handgun mammal muscular muscular_female pistol police ranged_weaponsolo street_lamp
sunrise tirrel uniform weapon
url: https://static1.e621.net/data/sample/d3/ae/d3aee9d4de485f2be935e84ebbd971b7.jpg
- tags: 2015 ambiguous_gender anthro blue_eyes clothing cosplay costume day detailed_background
dragon dreamworks falvie fudge_the_otter how_to_train_your_dragon kigurumi mammal
membranous_wings mustelid night_fury open_mouth otter outsidesitting sky smile
solo star starry_sky sunset toothless wings
url: https://static1.e621.net/data/sample/0f/d1/0fd1d92190633265fb32a800d65c82d7.jpg
- tags: holding_object food ambiguous_gender beverage black_fur blue_fur blush canine
chigiri clothing coffee cup first_person_view fur happy long_ears lucario mammal
nintendo one_eye_closed pokémon red_eyes sitting smile solo steam video_games wink
url: https://static1.e621.net/data/5a/c6/5ac6787ce0216184bb1737ffc97972e7.png
- tags: android animatronic anthro canine clothed clothing exposed_endoskeleton eye_patch
eyewear five_nights_at_freddy's fox foxy_(fnaf) fur hook hook_hand machine male
mammal naoren piratered_fur robot simple_background solo topless video_games white_background
yellow_eyes
url: https://static1.e621.net/data/17/0a/170ad0093d771d4b99c59f9626712578.png
- tags: 2015 finger_claws 5_fingers <3 anthro blush boss_monster breasts caprine claws
clothed clothing eyebrows eyelashes female fur gastropod goat hi-biki hi_res horn
long_ears looking_at_viewer mammal poserobe simple_background smile snail solo
toriel undertale video_games white_fur wide_hips
url: https://static1.e621.net/data/sample/31/16/31162bd0709f5c79726eb55a05997237.jpg
- tags: 2017 4_toes anthro arnou barefoot black_fur black_nose blue_eyes canine clothed
clothing cuddling day detailed_background digitigrade duo fur hoodie koul male
male/male mammal outside red_eyes smile toes tree wolf wulfcole
url: https://static1.e621.net/data/sample/e2/4e/e24e60d0e2604a1e18de6ec698462e75.jpg
- tags: 2014 anthro black_nose blue_eyes blush brown_fur clothed clothing collar countershade_face
countershading female flower flower_in_hair fur headshot_portrait kiki looking_away
mammal markings multicolored_fur mustelid open_mouth otter plant portrait rarakiesimple_background
solo spots teeth tongue two_tone_fur whiskers white_fur
url: https://static1.e621.net/data/8d/8e/8d8ec834c0b6bd02181510e3bc3f7e4d.png
- tags: pretending anthro antlers brown_fur cellphone cervine cloud deer duo feline
fur green_eyes hi_res horn humor imminent_death lion male mammal nbowa outside
phone predator/preyselfie sky tirrel tirrel_(character) tongue tongue_out tree
url: https://static1.e621.net/data/sample/d9/0e/d90ea5d58bbb37f6c08d054946a478f9.jpg
- tags: "... ambiguous_gender anthro black_fur blue_fur blush canine close-up crossed_arms
fur icon jia looking_at_viewer lucario mammal nintendo pokémon pokémon_(species) red_eyes
simple_background solo tan_fur video_games white_background"
url: https://static1.e621.net/data/sample/db/b6/dbb6db28e0514bb981f417edf6479c9a.jpg
- tags: winged_arms wings ... absurd_res anthro avian beak bird blush breath_of_the_wild
clothed clothing dialogue english_text feathers hi_res kass_(zelda) male muscular
muscular_male nintendo outsiderito sketch solo tacklebox text the_legend_of_zelda
video_games
url: https://static1.e621.net/data/sample/c6/a3/c6a32022972d9807cfaae5000f45b2c4.jpg
- tags: too_early_for_this 2014 5_fingers annoyed anthro beverage big_eyebrows black_eyebrows
black_eyes black_fur black_hair black_nose black_shirt blue_fur bust_portrait
canine clothed clothing coffee coffee_mug countertop crossed_arms cup dialogue
digital_media_(artwork) ear_piercing english_text eyebrows facial_hair facial_piercing
food fur gauged_ear goatee grumpy hair holding_cup holding_object hot_drink lip_piercing
lol_comments looking_at_viewer male mammal multicolored_fur multicolored_hair
nose_piercing nose_ring open_mouth piercing portrait profanityreaction_image restricted_palette
shirt signature simple_background sitting sky3 skye_blue solo speech_bubble steam
striped_ears table teeth text thick_eyebrows two_tone_fur two_tone_hair white_background
white_fur white_hair wolf
url: https://static1.e621.net/data/sample/16/61/1661025f6995846607e709c6da99e123.jpg
- tags: 2013 ambiguous_gender black_eyes cloud cloudscape colorful detailed_background
feral fish happy lol_comments marine open_mouth outside rainbow rainbow_archreaction_image
shark sky solo sparkles spunky_(artist) super_gay teeth
url: https://static1.e621.net/data/e5/03/e503e7d3465337448b715cfd6457edd0.jpg
- tags: 2017 anthro belly big_breasts breasts brown_hair canine chinese_clothing chinese_dress
cleavage cleavage_cutout clothed clothing dress female food fox gradient_background
hair hairclip hi_res kemono long_hair looking_at_viewer mammal purple_eyessetouchi_kurage
simple_background slightly_chubby solo voluptuous waiter wide_hips
url: https://static1.e621.net/data/sample/b1/0d/b10d8740126b4fb20d4b21920d131c8f.jpg
- tags: brown_hair orange_hair sitting striped_body striped_fur striped_tail 2018
<3 anthro black_topwear blue_eyes blue_topwear breasts clothed clothing collaboration
countershade_legs countershade_torso countershading day deymos digital_media_(artwork)
dipstick_tail domestic_cat felid feline felis female fingerless_(marking) flower
fully_clothed fur hair inside iskra legwear looking_aside mammal multicolored_body
multicolored_fur multicolored_tail orange_body orange_fur panties pink_nose plantshaded
shirt solo stripes sunflower tan_body tan_fur thigh_highs underwear url vera_(iskra)
white_legwear window
url: https://static1.e621.net/data/sample/80/8d/808d424fd5c3ccbaddac9fc5b92f028a.jpg
- tags: 2016 anthro blush buckteeth canine disney duo embarrassed english_text female
fireworks fox freedomthai fur green_eyes grey_fur half-closed_eyes hand_on_head
hi_res holding_object judy_hopps lagomorph larger_male long_ears male male/female
mammal nick_wilde night open_mouth orange_fur outside pen predator/prey purple_eyes
rabbitromantic_ambiance size_difference smaller_female smile smirk tears teeth
text zootopia
url: https://static1.e621.net/data/sample/c6/32/c6321f137f68f99f2bee51dba3bf1de5.jpg
- tags: ambiguous_gender capcom cub dragon horn kneeling kosian looking_at_viewer
membranous_wings monster_hunter red_eyes rukodiora scalie simple_background solo
video_games white_background wings young
url: https://static1.e621.net/data/sample/da/92/da922cd07342972262e98de824595cd1.jpg
- tags: 2014 anthro beach bikini bikini_top blue_eyes bottomless clothed clothing
cloud detailed_background digital_media_(artwork) ear_piercing falvie fangs female
grin hair looking_at_viewer mammal markings mustelid neck_tuft otter outside piercingsand
seaside short_hair sky smile solo swimsuit tuft water white_hair
url: https://static1.e621.net/data/sample/aa/3f/aa3f6074e6c14ff78b40ff51f109869b.jpg
- tags: casual_nudity day eyebrows eyelashes grey_hair half-closed_eyes looking_aside
multicolored_fur multicolored_hair partially_submerged skinny_dipping slim snout
sunlight swimming tan_fur thick_tail 2015 anthro back_muscles blonde_hair brown_eyes
brown_fur brown_hair brown_nose butt digital_media_(artwork) eyewear fangs female
feral fish fur goggles hair hi_res high-angle_view mammal marine mikhaila mouth_hold
mustelid nude otter patreonshort_hair solo teeth tsampikos water wet wide_hips
url: https://static1.e621.net/data/sample/82/ab/82abacf96b5e3bde9d92ef6e5e0197eb.jpg
- tags: 5_fingers anthro_on_anthro black_nose blush brown_fur brown_nose brown_stripes
brown_tail canid cheek_tuft chest_tuft embrace eyebrows felid fluffy fluffy_tail
gloves_(marking) glowing_ears glowing_fur glowing_spots green_fur green_spots
holding_object holding_plush humanoid_hands interspecies markings orange_tail
pantherine romantic_couple snout spots spotted_fur striped_fur striped_tail tan_belly
tan_fur tuft white_belly white_tail anthro bed bed_sheet bedding bioluminescence
brown_hair canine cuddling digital_media_(artwork) duo eyes_closed fox fur gabe_(mytigertail)
glowing hair hug inside lan lying male male/male mammal multicolored_fur mytigertail
nude on_bed on_side open_mouth orange_fur orange_stripes pillow plushie rating:q
sleeping smile spooning stripes tiger two_tone_fur white_fur zeta-haru
url: https://static1.e621.net/data/sample/b8/89/b889bbc7002cc1152ed7f1c8e3a14670.jpg
- tags: 2014 3:2 afternoon alien big_ears black_scales blue_eyes blue_fur blue_nose
claws clothed clothing cosplay costume crossover daww disney dragon dreamworks
duo experiment_(species) feral fish food fur grasp green_sclera hat head_tuft
headgear holding_food holding_object how_to_train_your_dragon inside lilo_and_stitch
long_ears looking_down looking_up lying male marine membranous_wings night_fury
no_sclera offering_(disambiguation) offering_food offering_to_another on_front
on_ground outstretched_arms raised_arm scales scalie scarf sharp_teeth size_difference
smile standing stitch sunlight teeth toe_claws toothless tsaoshin wings
url: https://static1.e621.net/data/50/cc/50cc1f4f731dca8cb66fdb9fd42bc57d.png
- tags: 2017 ambiguous_form ambiguous_gender big_ears brown_eyes canid canine derp_eyes
dipstick_ears ears_down english_text fangs felisrandomis fennec fox frown fur
headshot_portrait humor inner_ear_fluff lol_comments mammal multiple_poses open_mouth
open_smile portrait pose screaming simple_background smile solo tan_fur teeth
text the_truth tongue weasyl
url: https://static1.e621.net/data/79/d7/79d74e8154dcea5339ff51f77fd3c98b.png
- tags: 2018 anthro black_hair blue_eyes blush canid canine canis clothing domestic_dog
faceless_male female hair human male mammal on_lap sally_(povinne10) talilly tongue
tongue_out
url: https://static1.e621.net/data/08/1e/081e279f730cccb5948853e8d1ea6a9f.jpg
- tags: 2018 <3 ambiguous_gender blush coal_(rakkuguy) eyes_closed happy human kobold
mammal motion_lines one_eye_closed open_mouth petting rakkuguy scalie simple_background
smile tailwag tongue tongue_out white_background
url: https://static1.e621.net/data/48/5d/485d385d6bb518ee12c78747054e827c.jpg
- tags: 2018 <3 3_toes ambiguous/ambiguous ambiguous_gender anthro anthro_on_anthro
blue_fur butt canid canine cewljoke chest_tuft cute_fangs duo evolutionary_family
eyes_closed fur hindpaw hi_res hug kneeling level_difference lucario mammal nintendo
nude pawpads paws pink_pawpads pokémon pokémon_(species) red_eyes riolu signature
simple_background smile spikes toes tuft video_games white_background wholesome
url: https://static1.e621.net/data/69/14/6914390405ab241003e48b4cfeeea5f3.png
- tags: 2017 absurd_res ambiguous_gender anatomy black_background blep canid canine
cross-eyed diagram english_text feral fox fur hi_res humor mammal meme red_fox
riot_the_red_fox simple_background sitting solo text tongue tongue_out whiskers
zillion_ross
url: https://static1.e621.net/data/8b/a7/8ba7610b0a2b91d91aebf4a55e131aa7.png
- tags: 2018 4_toes anatomy black_background black_fur black_hair black_nose blue_fur
blue_hair blue_tongue canid canine claws diagram ear_piercing english_text feral
fox fur fur_markings gloves_(marking) hair hi_res humor industrial_piercing male
mammal markings meme mostly_nude multicolored_fur multicolored_hair open_mouth
original_character_do_not_steal owo owo_whats_this paws piercing quadruped restricted_palette
scarf simple_background socks_(marking) solo teeth text the_truth toe_claws toes
tongue two_tone_hair white_fur zillion_ross
url: https://static1.e621.net/data/63/3b/633bbadd77a49e662768428ffc026491.png
- tags: 2017 <3 alcohol avian beak beer beverage bird black_feathers bottle corvid
crow deep_throat digital_media_(artwork) english_text feathers feral hi_res humor
lol_comments oral oral_penetration penetration solo swish talons text wings
url: https://static1.e621.net/data/7c/d9/7cd90352fa57ddaeb3f422de355e727c.jpg
- tags: 2017 5_fingers alternate_form anthro canid canine clothed clothing cup cups_on_ears
cute_fangs dagger detailed_background dialogue digital_media_(artwork) dutch_angle
english_text fox fur gregg_(nitw) happy inside jacket knife koul looking_at_viewer
male mammal melee_weapon night_in_the_woods open_mouth orange_fur smile solo speech_bubble
text video_games weapon
url: https://static1.e621.net/data/4f/be/4fbe36ed49bf8d501edb8509a554837d.jpg
- tags: ambiguous_gender canid canine conditional_dnp daww derp_eyes digital_media_(artwork)
digital_painting_(artwork) ears_back eyes_closed feral flexible fluffy fox full-length_portrait
fur humor lol_comments mammal markings oops orange_fur paws playing portrait red_fox
side_view simple_background snow socks_(marking) solo trunchbull upside_down whiskers
white_background white_fur
url: https://static1.e621.net/data/94/d1/94d108d2e4ed476a113f93e7768accce.jpg
- tags: anthro canid canine clothed clothing english_text fangs female fur hair image_macro
impact_(font) jurassic_park mammal meme nasusbot open_mouth parody profanity reaction_image
skrillex smile solo teeth text
url: https://static1.e621.net/data/cb/a4/cba428d3227dd7358dbf63787c759e8d.png
- tags: "<3 3_toes ambiguous_gender anthro barefoot biped black_fur black_markings
blue_fur blue_tail blush canid canine cel_shading cheek_tuft collar digital_media_(artwork)
digitigrade facial_markings feet fur fur_tuft gloves_(marking) gradient_background
kneeling leash leash_in_mouth lucario mammal markings mouth_hold multicolored_fur
neck_tuft nintendo nude object_in_mouth paws pink_background pokémon pokémon_(species)
pseudo_clothing rakkuguy red_eyes shaded side_view simple_background smile snout
solo spikes submissive toes tuft video_games white_background yellow_fur"
url: https://static1.e621.net/data/a1/1e/a11e49bd7c556049770b3e905e9528ef.png
- tags: 2013 4_fingers anthro barefoot beverage black_fur black_nose canid canine
clothed clothing coffee coffee_mug cup dipstick_ears dipstick_tail english_text
eyes_closed fennec fingerless_(marking) fluffy fluffy_tail food fox fully_clothed
fur gloves_(marking) hair hi_res inner_ear_fluff lying male mammal markings multicolored_tail
orange_fur orange_hair pants reaching shirt side_view simple_background sleeping
socks_(marking) solo sound_effects text thanshuhai tired toeless_(marking) tongue
tongue_out white_background white_fur zzz
url: https://static1.e621.net/data/8d/eb/8deb2ae9fe81f9f6383a24c591bdd3be.png
- tags: 2016 alolan_vulpix altered_reflection ambiguous_gender black_nose brown_eyes
brown_hair canid canine contrast digital_media_(artwork) duality feral fur grey_nose
hair hindpaw hi_res inner_ear_fluff looking_at_viewer mammal multi_tail nintendo
paws pokémon pokémon_(species) realistic reflection regional_variant solo split_screen
standing symmetry tamberella tan_fur video_games vulpix white_fur
url: https://static1.e621.net/data/7e/11/7e11e929a5c5b58078d600d3aa23cf21.jpg
- tags: anthro canid canine clothed clothing disney edit english_text fox fully_clothed
gradient_background lyrics male mammal michael_jackson music nick_wilde simple_background
smile smooth_criminal solo song sound text zootopia 羽默空_(artist)
url: https://static1.e621.net/data/fc/09/fc090f0332c2ae9e91bb6953179bceaf.jpg
- tags: anthro antlers brown_fur cellphone cervid cloud duo felid fur green_eyes hi_res
horn humor imminent_death lion male mammal nbowa outside pantherine phone predator/prey
pretending selfie sky tirrel tirrel_(character) tongue tongue_out tree
url: https://static1.e621.net/data/d9/0e/d90ea5d58bbb37f6c08d054946a478f9.jpg
- tags: 2016 anthro black_fur black_hair black_nose blizzard_entertainment bound breasts
canid canine cheek_tuft conditional_dnp crying digital_media_(artwork) domestic_cat
dream_eater duo e621 english_text eyelashes fan_character felid feline felis female
feral floof flora_fauna fluffy food food_creature fruit fur green_eyes hair hi_res
horn humor impact_(font) kingdom_hearts lol_comments looking_up mammal melon meloncat
melonyan meme meow_wow meta nude paralee_(character) plant poof profanity rainbow
ratte sad square_enix tardar_sauce tears technicolor_yawn text tuft video_games
vomit wall_of_text warcraft watermelon were werecanid werecanine werewolf worgen
url: https://static1.e621.net/data/42/2a/422aaf2c210d6e0e48480ce419b06896.png
- tags: 2016 <3 4_fingers abstract_background anthro asriel_dreemurr big_eyes black_background
blush boss_monster bovid braeburned brown_background caprine cheek_tuft clothing
cute_fangs digital_media_(artwork) fangs feels fur gesture goat gradient_background
green_clothing green_topwear hair half-length_portrait hand_heart head_tuft hi_res
long_ears looking_at_viewer love male mammal multicolored_clothing open_mouth
pink_tongue portrait sharp_teeth signature simple_background smile solo sweater
teeth tongue tuft undertale video_games white_fur yellow_bottomwear yellow_clothing
young
url: https://static1.e621.net/data/14/e7/14e7eff45c61ba29e02f4f59846dc6bc.png
- tags: "... <3 absurd_res ambiguous_gender beady_eyes blep dialogue english_text
feral forked_tongue hi_res iron_and_whine python reptile scalie simple_background
snake solo text tongue tongue_out traditional_media_(artwork) white_background"
url: https://static1.e621.net/data/7f/6a/7f6af5deef179238510cfa1d606ef81f.jpg
- tags: 2016 alantka anthro canid canine cuddling detailed_background disney duo embrace
eyes_closed female forest fox fur gloves_(marking) green_eyes grey_fur judy_hopps
lagomorph long_ears looking_down male mammal markings nick_wilde orange_fur outside
predator/prey rabbit romantic_couple size_difference smile style_parody tree zootopia
url: https://static1.e621.net/data/e1/28/e128617350d9e02bf816f0d4d529c210.jpg
- tags: 2016 absurd_res anthro barefoot bed bedroom bracelet buckteeth canid canine
choker dancing dennyvixen dipstick_tail disney duo earbuds eyes_closed female
fox fur gloves_(marking) good_morning grey_fur happy headphones hi_res inner_ear_fluff
inside ipod ipod_nano jewelry judy_hopps lagomorph long_ears male mammal markings
multicolored_tail nick_wilde on_bed open_mouth orange_fur pawpads portable_music_player
predator/prey rabbit smile teeth two_tone_tail upscale zootopia
url: https://static1.e621.net/data/2e/d4/2ed4a63c7105f9e6ca099033403b242a.png
- tags: ">.< :< :> :| •≠• :3 ambiguous_gender black_eyes :d d: expressions food_creature
frown group humor looking_at_viewer low_res mint not_furry :o o3o open_mouth plastic
real smile tic_tac tongue tongue_out w4nw4n x_x"
url: https://static1.e621.net/data/e5/1e/e51edfb8ec608817cca55d9bf7579c47.jpg
- tags: absurd_res anthro bed bouquet canid canine canis clothing duo eyes_closed
female flower_bouquet hair hi_res human larger_anthro larger_female male mammal
size_difference sleeping smaller_human smaller_male spooning vanchamarl were werecanid
werecanine werewolf wholesome wolf zephra
url: https://static1.e621.net/data/14/b5/14b5352ee09a0dee5a565f5c0e6bfb3c.png
- tags: 2016 anthro blue_eyes boss_monster bovid caprine cellphone crossover disney
english_text female fur goat holding_object horn image_macro long_ears mammal
meme monsters_inc open_mouth parody phone pixar reaction_image solo sulley taken_(movie)
text toriel undertale video_games white_fur wolfjedisamuel
url: https://static1.e621.net/data/fb/52/fb52b8b36ecb85eaf155855a23e70f24.png
- tags: animated anthro asriel_dreemurr blush boss_monster bovid caprine clothing
computer edit empty_eyes english_text floppy_ears goat happy hyperactive lol_comments
male mammal o_o simple_background smile solo text undertale undertale-tales video_games
url: https://static1.e621.net/data/bf/3c/bf3ce93ea4f3e7e3719c59b6557343b0.gif
- tags: 2016 angry anthro antlers bell cervid collar computer furry_problems green_eyes
horn laptop lol_comments male mammal reaction_image solo tirrel tirrel_(character)
url: https://static1.e621.net/data/9c/39/9c39de16aa06ea3afbc0ca4cd3137960.jpg
- tags: anthro big_breasts black_fur black_nose blue_eyes breasts claws clothed clothing
english_text female fur giant_panda gillpanda gillpanda_(character) looking_at_viewer
mammal morbidly_obese motivational_poster multicolored_fur obese overweight overweight_female
pawpads pen sharp_teeth simple_background smile solo teeth text thumbs_up two_tone_fur
ursid white_background white_fur
url: https://static1.e621.net/data/fa/67/fa67485134b0ee19fdaa49a68161f4f5.jpg
- tags: 2015 anthro asriel_dreemurr big_eyes boss_monster bovid caprine clothed clothing
fangs fatz_geronimo goat hoodie horn long_ears male mammal purple_background reaction_image
simple_background solo undertale video_games wide_eyed
url: https://static1.e621.net/data/f1/8d/f18db1184cf4c62d7afbdf8fd28f39f7.png
- tags: 2015 anatomy anthro asriel_dreemurr boss_monster bovid bukoya-star caprine
chart child clothed clothing cub english_text flower fur goat green_eyes grey_background
hi_res long_ears looking_at_viewer male mammal open_mouth plant simple_background
solo text undertale video_games white_fur young
url: https://static1.e621.net/data/b6/33/b633e381a700c619f7ea22666cf6b93d.jpg
- tags: 2015 <3 anthro asriel_dreemurr_(god_form) blue_background boss_monster bovid
caprine clothed clothing digital_media_(artwork) eating fluffy_hair fur gem goat
hair horn looking_at_viewer male mammal pocky red_eyes robe saturnspace simple_background
solo undertale video_games white_fur white_hair
url: https://static1.e621.net/data/8b/80/8b8000f1845841e50515eb0aa224abfb.png
- tags: 2015 ambiguous_gender baseball_cap beady_eyes black_eyes digital_media_(artwork)
feral forked_tongue grey_tongue half-length_portrait hat lol_comments meme mostly_nude
portrait purple_headwear python reptile scalie simple_background smile snake solo
tongue tongue_out unknown_artist white_background
url: https://static1.e621.net/data/bf/f6/bff630817262325b514eee7ff197802e.png
- tags: 2015 ambiguous_gender avian beak bird bread cere_(feature) columbid common_pigeon
crumbs cryptid-creations derp_eyes doing_it_wrong feathers feral flour folded_wings
food humor in_bread lol_comments meme pigeon red_eyes simple_background solo watermark
what white_background
url: https://static1.e621.net/data/f9/1f/f91f92ac563c3bbe4e569d68a46dfafe.png
- tags: 2015 ambiguous_gender anthro blue_eyes clothing cosplay costume day detailed_background
dragon dreamworks falvie fudge_the_otter how_to_train_your_dragon kigurumi mammal
membranous_wings mustelid night_fury open_mouth otter outside sitting sky smile
solo star starry_sky sunset toothless wings
url: https://static1.e621.net/data/0f/d1/0fd1d92190633265fb32a800d65c82d7.png
- tags: 2015 5_fingers ambiguous_gender anthro black_lips black_nose canid canine
canis controller domestic_cat duo eye_contact felid feline felis fluffy fluffy_tail
fur grey_fur handpaw hax_(artist) inside jackal kenket lamp lofi long_mouth looking_at_another
looking_down looking_up lying mammal no_sclera nude on_back orange_eyes pawpads
paws pink_nose reaching remote_control romantic_couple shaded side_view slice_of_life
smile snout sofa table tv_remote whiskers white_fur yellow_eyes
url: https://static1.e621.net/data/0c/09/0c09080148c52ed89f16fe8fbc731dcf.jpg
- tags: 2012 anthro beverage black_fur building cafe camera_view canid canine car
chair cheek_tuft clothed clothing coffee coffee_mug coffee_shop cup detailed_background
digital_media_(artwork) eyebrows fog food fox fur green_eyes hair half-length_portrait
high-angle_view inside looking_at_viewer male mammal multicolored_fur orange_fur
orange_hair portrait red_fox selfie sitting slice_of_life smile solo table thanshuhai
tuft vehicle white_fur
url: https://static1.e621.net/data/a0/47/a0476a240b0b780b926d831a3e6426ea.png
- tags: angry blue_body blue_eyes blue_hair blush dialogue english_text equine eyelashes
eyes_closed female friendship_is_magic hair horn horse humor long_hair mammal
my_little_pony open_mouth orange_background pink_tongue princess_luna_(mlp) profanity
reaction_image simple_background solo sweat teeth text the_truth tongue unknown_artist
winged_unicorn wings
url: https://static1.e621.net/data/ef/e5/efe507d244c5841d8496ce52f4f706a6.png
- tags: "... ambiguous_gender bed bedding black_fur blanket checkered_background domestic_cat
english_text felid feline felis female fur garfield_(series) lying mae_(nitw)
mammal night_in_the_woods on_bed on_front pattern_background reaction_image simple_background
solo speech_bubble text under_covers unknown_artist video_games"
url: https://static1.e621.net/data/19/43/194344f13372ea3e80ef007dd56463c2.png
- tags: 2015 anthro cheetah clothed clothing detailed_background felid feline female
flashlight fully_clothed gun handgun holding_object mammal menacing muscular muscular_female
outside pistol police ranged_weapon solo standing street_lamp sunrise tirrel uniform
weapon yellow_sclera
url: https://static1.e621.net/data/d3/ae/d3aee9d4de485f2be935e84ebbd971b7.jpg
- tags: 2015 anthro antlers bell blue_eyes brown_hair canid canine car cervid cheetah
clothed clothing collar comic dialogue driver driving duo english_text felid feline
female green_eyes hair hat headlight hi_res horn humor inside_car male mammal
outside police profanity running text tirrel tirrel_(character) uniform vehicle
url: https://static1.e621.net/data/ed/e7/ede74f19c7adc6115fb751d729eceaf8.jpg
- tags: 2013 ambiguous_gender angry brown_fur canid canine chibi dipstick_tail english_text
feral fox fur humor mammal markings multicolored_fur multicolored_tail orange_fur
profanity running serious simple_background socks_(marking) solo technicolorpie
technicolor_pie text two_tone_tail white_background white_fur yellow_fur
url: https://static1.e621.net/data/44/53/4453fcdd6d4ce1cf6d6da88c9a35bafc.png
- tags: 2013 abstract_background ambiguous_gender anthro arm_support blonde_hair bow_tie
bust_portrait clothed clothing coat cosplay digital_media_(artwork) felid fur
gene_wilder hair half-closed_eyes hat humor inner_ear_fluff leaning_on_elbow lol_comments
long_hair low_res mammal meme pantherine parody portrait reaction_image smile
solo tassy tiger top_hat willy_wonka willy_wonka_and_the_chocolate_factory yellow_eyes
yellow_fur
url: https://static1.e621.net/data/d1/bb/d1bbf569513c5acf13b1be36d1d64bff.png
- tags: begging begging_pose blue_fur blue_tail canid canine chest_tuft conditional_dnp
dipstick_tail facial_markings fan_character feral feralized fluffy fur looking_away
male mammal markings mask_(marking) multicolored_fur multicolored_tail nintendo
pokémon pokémon_(species) portrait red_eyes riolu simple_background smile solo
tuft two_tone_fur two_tone_tail umpherio_(umpherio) video_games white_background
white_fur white_tail xnirox
url: https://static1.e621.net/data/97/38/973887346d669d97c7a75b7324855773.png
- tags: 2014 <3 anthro avian beak bird black_eyes black_nose blue_body blue_feathers
blue_jay blush brown_fur cartoon_network chest_tuft comic corvid dialogue duo
english_text eyes_closed fangs feathers fur grey_beak hi_res kissing kissing_cheek
love male male/male mammal markings mordecai_(regular_show) open_beak open_mouth
procyonid raccoon regular_show rigby_(regular_show) romantic_couple simple_background
stripes surprise tan_fur teeth text tongue tuft white_background white_body white_feathers
wholesome xiamtheferret
url: https://static1.e621.net/data/ca/c9/cac98850f5b5b48440c100ad800caac1.png
- tags: anthro blonde_hair blue_eyes bone_necklace breasts carnivore clothed clothing
digital_media_(artwork) domestic_cat eating eyebrows felid feline felis female
food front_view hair half-length_portrait holding_food holding_object inuki inuki_(character)
jewelry mammal meat melloque necklace pink_nose ponytail portrait shirt shirt_logo
signature simple_background smile solo steak teeth
url: https://static1.e621.net/data/63/43/63433706609c428f2027986940547834.png
- tags: 2015 applejack_(mlp) blonde_hair cutie_mark earth_pony equine face_paint feathers
female feral friendship_is_magic green_eyes hair headdress hi_res horse jewelry
looking_at_viewer mammal my_little_pony native_american necklace pony portrait
santagiera solo teeth
url: https://static1.e621.net/data/ac/85/ac85e5ea07ae712946bb897bff734d59.jpg
- tags: 2015 animatronic anthro avian beak beverage bird blue_eyes blush bonnie_(fnaf)
canid canine cellphone chica_(fnaf) chicken eye_patch eyewear five_nights_at_freddy's
food fox foxy_(fnaf) freddy_(fnaf) group happy hat humor kissing lagomorph laugh
looking_away machine male male/male mammal phone purple_eyes rabbit robot smile
spin_the_bottle ursid video_games xiamtheferret yellow_eyes
url: https://static1.e621.net/data/be/55/be5581393bcf2451ca90c16ba48c694c.png
- tags: 2014 anthro antiander blue_eyes canid canine clothed clothing dress feathered_wings
feathers female fox gloves hair heterochromia hi_res holly_(plant) long_hair mammal
plant solo source_request white_hair wings
url: https://static1.e621.net/data/7c/8a/7c8a07df68f6b8c93d425158396df811.png
- tags: 2012 ambiguous_gender black_fur black_nose eeveelution fadingsky feral fire
fur markings nintendo pink_background pokémon pokémon_(species) red_eyes simple_background
smoke solo umbreon video_games yellow_markings
url: https://static1.e621.net/data/d8/2f/d82fc9c3bfa78c17db4d117950063124.png
- tags: 2014 ass_up avian beak blue_eyes blue_fur braeburned digital_media_(artwork)
earth_pony equine feathered_wings feathers female feral friendship_is_magic fur
gilda_(mlp) group gryphon hair horse laser laser_pointer mammal multicolored_hair
my_little_pony pegasus pink_fur pink_hair pinkie_pie_(mlp) pony purple_eyes rainbow_dash_(mlp)
rainbow_hair tongue tongue_out wings yellow_eyes
url: https://static1.e621.net/data/8c/08/8c08e77a944dd6df29eb3e908f5bd93f.png
- tags: ambiguous_gender anthro bust_portrait canid canine canis close-up darkwingo
dingo eye_reflection fluffy green_background green_eyes head_tilt hi_res hybrid
jewelry mammal markings necklace portrait scar simple_background smile solo thanshuhai
wolf
url: https://static1.e621.net/data/d7/10/d710ff227b96e59a655d152ac2fcc9f7.jpg
- tags: 2014 <3 anthro beverage beverage_can black_hair blue_hair blue_highlights
clothing collar digital_media_(artwork) domestic_cat fangs felid feline felis
female food gradient_hair green_eyes hair highlights jacket looking_at_viewer
mammal smile solo tentacletongue wolfy-nail young
url: https://static1.e621.net/data/86/94/86942ce7f5be8ba952fef914c5593d2e.jpg
- tags: 2012 ambiguous_gender bed bedding blanket blue_eyes eeveelution feral hi_res
looking_at_viewer lying nintendo on_bed on_front open_mouth pawpads pokémon pokémon_(species)
shadow solo tartii under_covers vaporeon video_games watermark
url: https://static1.e621.net/data/c0/d4/c0d4964ebc0fb0eeddb61bc03cbc6a2b.jpg
- tags: 2014 5:4 anthro atryl avian beak black_feathers brown_feathers cloud digital_media_(artwork)
duo eye_contact feathered_wings feathers female friendship_is_magic genevieve_(mlp)
grass greta_(mlp) grey_eyes gryphon hug my_little_pony one_eye_closed outside
sky smile white_feathers wings wink
url: https://static1.e621.net/data/67/c9/67c952de260ede67d0fe507bb99d3a6e.png
- tags: 2014 3_toes ambiguous_gender animated anthro ass_up black_scales butt digitigrade
dragon felid feral group hindpaw humor inside_train lamp loop low_res male mammal
membranous_wings metro multicolored_scales paws pushing rubble scales scalie size_difference
solo_focus subway tirrel toes train tunnel two_tone_scales vehicle white_scales
wings
url: https://static1.e621.net/data/7d/0d/7d0de8443bad63b6bd56a24ca0d0fb98.gif
images:
- tags: zoodystopia 2016 anthro bandage black_nose brown_fur canine clothed clothing
collar disney fox fur gloves_(marking) green_eyes looking_at_viewer male mammal
markings multicolored_fur nick_wilde open_shirt orange_fur pantssad shirt shock_collar
simple_background solo standing turningtides_(artist) white_background zootopia
url: https://static1.e621.net/data/87/8f/878f64f8df553ce09218bc9b1083b4e3.png
- tags: 5:4 2016 3_toes anthro barefoot canine claws clothed clothing cuddling disney
duo fabienne_growley female flat_chested fox green_eyes ipoke judy_hopps lagomorph
male mammal nick_wilde peter_moosebridge phone purple_eyes rabbit sitting smile
sofa soles television toes zootopia
url: https://static1.e621.net/data/62/f1/62f197461e755a7d4bd5884dc8ff20d6.jpg
- tags: begging begging_pose blue_fur blue_tail canine chest_tuft dipstick_tail facial_markings
fan_character feral feralized fluffy fur looking_away male mammal markings mask_(marking)
multicolored_fur multicolored_tail nintendo pokémon pokémon_(species) portrait red_eyes
riolu simple_background smile solo tuft two_tone_fur two_tone_tail umpherio_(umpherio)
video_games white_background white_fur white_tail xnirox
url: https://static1.e621.net/data/97/38/973887346d669d97c7a75b7324855773.png
- tags: felid pantherine 2017 armor big_breasts black_lips blue_eyes blue_hair bodysuit
breasts clothed clothing f-r95 female fingerless_gloves fluffy fluffy_tail gloves
hair inner_ear_fluff inside knee_pads long_tail looking_away looking_outside mammal
pink_noseshoulder_pads sitting skinsuit snow_leopard solo space spots tight_clothing
toeless_footwear yuna_snowleopard
url: https://static1.e621.net/data/34/7f/347fec14942b176b074c1cad64c31ad2.png
- tags: back_muscles 2015 anthro ass_up bed bedroom black_fur black_stripes book bookshelf
butt crawling feline fireplace fur green_eyes hax_(artist) inside kenket lofi
lying male mammal morning multicolored_fur nude on_floor on_front one_eye_closed
orange_fur painting pawpads platerug shaded solo striped_body stripes table tiger
vase white_fur window
url: https://static1.e621.net/data/sample/6f/f4/6ff406e64fe870f43512d863a8fd119b.jpg
- tags: pink_eyes 2018 anthro canine clothed clothing cookie digital_media_(artwork)
dog female food fur hair looking_at_viewer mammal nana_(fadey) open_mouthsmile
solo standing tofu93
url: https://static1.e621.net/data/sample/0f/01/0f01bc5401835aa1a082b19e83a0e956.jpg
- tags: 2013 anthro beverage blue_fur blue_hair borny_(character) canine clothing
coffee digital_media_(artwork) food fox fur green_eyes hair hoodie male mammal
open_mouth phonesolo wolfy-nail
url: https://static1.e621.net/data/sample/ac/9f/ac9f231b988d4b6f43b66e89e1d5578e.jpg
- tags: clothed detailed_background fully_clothed holding_object menacing outside
standing yellow_sclera 2015 anthro cheetah clothing feline female flashlight gun
handgun mammal muscular muscular_female pistol police ranged_weaponsolo street_lamp
sunrise tirrel uniform weapon
url: https://static1.e621.net/data/sample/d3/ae/d3aee9d4de485f2be935e84ebbd971b7.jpg
- tags: 2015 ambiguous_gender anthro blue_eyes clothing cosplay costume day detailed_background
dragon dreamworks falvie fudge_the_otter how_to_train_your_dragon kigurumi mammal
membranous_wings mustelid night_fury open_mouth otter outsidesitting sky smile
solo star starry_sky sunset toothless wings
url: https://static1.e621.net/data/sample/0f/d1/0fd1d92190633265fb32a800d65c82d7.jpg
- tags: holding_object food ambiguous_gender beverage black_fur blue_fur blush canine
chigiri clothing coffee cup first_person_view fur happy long_ears lucario mammal
nintendo one_eye_closed pokémon red_eyes sitting smile solo steam video_games wink
url: https://static1.e621.net/data/5a/c6/5ac6787ce0216184bb1737ffc97972e7.png
- tags: android animatronic anthro canine clothed clothing exposed_endoskeleton eye_patch
eyewear five_nights_at_freddy's fox foxy_(fnaf) fur hook hook_hand machine male
mammal naoren piratered_fur robot simple_background solo topless video_games white_background
yellow_eyes
url: https://static1.e621.net/data/17/0a/170ad0093d771d4b99c59f9626712578.png
- tags: 2015 finger_claws 5_fingers <3 anthro blush boss_monster breasts caprine claws
clothed clothing eyebrows eyelashes female fur gastropod goat hi-biki hi_res horn
long_ears looking_at_viewer mammal poserobe simple_background smile snail solo
toriel undertale video_games white_fur wide_hips
url: https://static1.e621.net/data/sample/31/16/31162bd0709f5c79726eb55a05997237.jpg
- tags: 2017 4_toes anthro arnou barefoot black_fur black_nose blue_eyes canine clothed
clothing cuddling day detailed_background digitigrade duo fur hoodie koul male
male/male mammal outside red_eyes smile toes tree wolf wulfcole
url: https://static1.e621.net/data/sample/e2/4e/e24e60d0e2604a1e18de6ec698462e75.jpg
- tags: 2014 anthro black_nose blue_eyes blush brown_fur clothed clothing collar countershade_face
countershading female flower flower_in_hair fur headshot_portrait kiki looking_away
mammal markings multicolored_fur mustelid open_mouth otter plant portrait rarakiesimple_background
solo spots teeth tongue two_tone_fur whiskers white_fur
url: https://static1.e621.net/data/8d/8e/8d8ec834c0b6bd02181510e3bc3f7e4d.png
- tags: pretending anthro antlers brown_fur cellphone cervine cloud deer duo feline
fur green_eyes hi_res horn humor imminent_death lion male mammal nbowa outside
phone predator/preyselfie sky tirrel tirrel_(character) tongue tongue_out tree
url: https://static1.e621.net/data/sample/d9/0e/d90ea5d58bbb37f6c08d054946a478f9.jpg
- tags: "... ambiguous_gender anthro black_fur blue_fur blush canine close-up crossed_arms
fur icon jia looking_at_viewer lucario mammal nintendo pokémon pokémon_(species) red_eyes
simple_background solo tan_fur video_games white_background"
url: https://static1.e621.net/data/sample/db/b6/dbb6db28e0514bb981f417edf6479c9a.jpg
- tags: winged_arms wings ... absurd_res anthro avian beak bird blush breath_of_the_wild
clothed clothing dialogue english_text feathers hi_res kass_(zelda) male muscular
muscular_male nintendo outsiderito sketch solo tacklebox text the_legend_of_zelda
video_games
url: https://static1.e621.net/data/sample/c6/a3/c6a32022972d9807cfaae5000f45b2c4.jpg
- tags: too_early_for_this 2014 5_fingers annoyed anthro beverage big_eyebrows black_eyebrows
black_eyes black_fur black_hair black_nose black_shirt blue_fur bust_portrait
canine clothed clothing coffee coffee_mug countertop crossed_arms cup dialogue
digital_media_(artwork) ear_piercing english_text eyebrows facial_hair facial_piercing
food fur gauged_ear goatee grumpy hair holding_cup holding_object hot_drink lip_piercing
lol_comments looking_at_viewer male mammal multicolored_fur multicolored_hair
nose_piercing nose_ring open_mouth piercing portrait profanityreaction_image restricted_palette
shirt signature simple_background sitting sky3 skye_blue solo speech_bubble steam
striped_ears table teeth text thick_eyebrows two_tone_fur two_tone_hair white_background
white_fur white_hair wolf
url: https://static1.e621.net/data/sample/16/61/1661025f6995846607e709c6da99e123.jpg
- tags: 2013 ambiguous_gender black_eyes cloud cloudscape colorful detailed_background
feral fish happy lol_comments marine open_mouth outside rainbow rainbow_archreaction_image
shark sky solo sparkles spunky_(artist) super_gay teeth
url: https://static1.e621.net/data/e5/03/e503e7d3465337448b715cfd6457edd0.jpg
- tags: 2017 anthro belly big_breasts breasts brown_hair canine chinese_clothing chinese_dress
cleavage cleavage_cutout clothed clothing dress female food fox gradient_background
hair hairclip hi_res kemono long_hair looking_at_viewer mammal purple_eyessetouchi_kurage
simple_background slightly_chubby solo voluptuous waiter wide_hips
url: https://static1.e621.net/data/sample/b1/0d/b10d8740126b4fb20d4b21920d131c8f.jpg
- tags: brown_hair orange_hair sitting striped_body striped_fur striped_tail 2018
<3 anthro black_topwear blue_eyes blue_topwear breasts clothed clothing collaboration
countershade_legs countershade_torso countershading day deymos digital_media_(artwork)
dipstick_tail domestic_cat felid feline felis female fingerless_(marking) flower
fully_clothed fur hair inside iskra legwear looking_aside mammal multicolored_body
multicolored_fur multicolored_tail orange_body orange_fur panties pink_nose plantshaded
shirt solo stripes sunflower tan_body tan_fur thigh_highs underwear url vera_(iskra)
white_legwear window
url: https://static1.e621.net/data/sample/80/8d/808d424fd5c3ccbaddac9fc5b92f028a.jpg
- tags: 2016 anthro blush buckteeth canine disney duo embarrassed english_text female
fireworks fox freedomthai fur green_eyes grey_fur half-closed_eyes hand_on_head
hi_res holding_object judy_hopps lagomorph larger_male long_ears male male/female
mammal nick_wilde night open_mouth orange_fur outside pen predator/prey purple_eyes
rabbitromantic_ambiance size_difference smaller_female smile smirk tears teeth
text zootopia
url: https://static1.e621.net/data/sample/c6/32/c6321f137f68f99f2bee51dba3bf1de5.jpg
- tags: ambiguous_gender capcom cub dragon horn kneeling kosian looking_at_viewer
membranous_wings monster_hunter red_eyes rukodiora scalie simple_background solo
video_games white_background wings young
url: https://static1.e621.net/data/sample/da/92/da922cd07342972262e98de824595cd1.jpg
- tags: 2014 anthro beach bikini bikini_top blue_eyes bottomless clothed clothing
cloud detailed_background digital_media_(artwork) ear_piercing falvie fangs female
grin hair looking_at_viewer mammal markings mustelid neck_tuft otter outside piercingsand
seaside short_hair sky smile solo swimsuit tuft water white_hair
url: https://static1.e621.net/data/sample/aa/3f/aa3f6074e6c14ff78b40ff51f109869b.jpg
- tags: casual_nudity day eyebrows eyelashes grey_hair half-closed_eyes looking_aside
multicolored_fur multicolored_hair partially_submerged skinny_dipping slim snout
sunlight swimming tan_fur thick_tail 2015 anthro back_muscles blonde_hair brown_eyes
brown_fur brown_hair brown_nose butt digital_media_(artwork) eyewear fangs female
feral fish fur goggles hair hi_res high-angle_view mammal marine mikhaila mouth_hold
mustelid nude otter patreonshort_hair solo teeth tsampikos water wet wide_hips
url: https://static1.e621.net/data/sample/82/ab/82abacf96b5e3bde9d92ef6e5e0197eb.jpg
- tags: 5_fingers anthro_on_anthro black_nose blush brown_fur brown_nose brown_stripes
brown_tail canid cheek_tuft chest_tuft embrace eyebrows felid fluffy fluffy_tail
gloves_(marking) glowing_ears glowing_fur glowing_spots green_fur green_spots
holding_object holding_plush humanoid_hands interspecies markings orange_tail
pantherine romantic_couple snout spots spotted_fur striped_fur striped_tail tan_belly
tan_fur tuft white_belly white_tail anthro bed bed_sheet bedding bioluminescence
brown_hair canine cuddling digital_media_(artwork) duo eyes_closed fox fur gabe_(mytigertail)
glowing hair hug inside lan lying male male/male mammal multicolored_fur mytigertail
nude on_bed on_side open_mouth orange_fur orange_stripes pillow plushie rating:q
sleeping smile spooning stripes tiger two_tone_fur white_fur zeta-haru
url: https://static1.e621.net/data/sample/b8/89/b889bbc7002cc1152ed7f1c8e3a14670.jpg
- tags: 2014 3:2 afternoon alien big_ears black_scales blue_eyes blue_fur blue_nose
claws clothed clothing cosplay costume crossover daww disney dragon dreamworks
duo experiment_(species) feral fish food fur grasp green_sclera hat head_tuft
headgear holding_food holding_object how_to_train_your_dragon inside lilo_and_stitch
long_ears looking_down looking_up lying male marine membranous_wings night_fury
no_sclera offering_(disambiguation) offering_food offering_to_another on_front
on_ground outstretched_arms raised_arm scales scalie scarf sharp_teeth size_difference
smile standing stitch sunlight teeth toe_claws toothless tsaoshin wings
url: https://static1.e621.net/data/50/cc/50cc1f4f731dca8cb66fdb9fd42bc57d.png
- tags: 2017 ambiguous_form ambiguous_gender big_ears brown_eyes canid canine derp_eyes
dipstick_ears ears_down english_text fangs felisrandomis fennec fox frown fur
headshot_portrait humor inner_ear_fluff lol_comments mammal multiple_poses open_mouth
open_smile portrait pose screaming simple_background smile solo tan_fur teeth
text the_truth tongue weasyl
url: https://static1.e621.net/data/79/d7/79d74e8154dcea5339ff51f77fd3c98b.png
- tags: 2018 anthro black_hair blue_eyes blush canid canine canis clothing domestic_dog
faceless_male female hair human male mammal on_lap sally_(povinne10) talilly tongue
tongue_out
url: https://static1.e621.net/data/08/1e/081e279f730cccb5948853e8d1ea6a9f.jpg
- tags: 2018 <3 ambiguous_gender blush coal_(rakkuguy) eyes_closed happy human kobold
mammal motion_lines one_eye_closed open_mouth petting rakkuguy scalie simple_background
smile tailwag tongue tongue_out white_background
url: https://static1.e621.net/data/48/5d/485d385d6bb518ee12c78747054e827c.jpg
- tags: 2018 <3 3_toes ambiguous/ambiguous ambiguous_gender anthro anthro_on_anthro
blue_fur butt canid canine cewljoke chest_tuft cute_fangs duo evolutionary_family
eyes_closed fur hindpaw hi_res hug kneeling level_difference lucario mammal nintendo
nude pawpads paws pink_pawpads pokémon pokémon_(species) red_eyes riolu signature
simple_background smile spikes toes tuft video_games white_background wholesome
url: https://static1.e621.net/data/69/14/6914390405ab241003e48b4cfeeea5f3.png
- tags: 2017 absurd_res ambiguous_gender anatomy black_background blep canid canine
cross-eyed diagram english_text feral fox fur hi_res humor mammal meme red_fox
riot_the_red_fox simple_background sitting solo text tongue tongue_out whiskers
zillion_ross
url: https://static1.e621.net/data/8b/a7/8ba7610b0a2b91d91aebf4a55e131aa7.png
- tags: 2018 4_toes anatomy black_background black_fur black_hair black_nose blue_fur
blue_hair blue_tongue canid canine claws diagram ear_piercing english_text feral
fox fur fur_markings gloves_(marking) hair hi_res humor industrial_piercing male
mammal markings meme mostly_nude multicolored_fur multicolored_hair open_mouth
original_character_do_not_steal owo owo_whats_this paws piercing quadruped restricted_palette
scarf simple_background socks_(marking) solo teeth text the_truth toe_claws toes
tongue two_tone_hair white_fur zillion_ross
url: https://static1.e621.net/data/63/3b/633bbadd77a49e662768428ffc026491.png
- tags: 2017 <3 alcohol avian beak beer beverage bird black_feathers bottle corvid
crow deep_throat digital_media_(artwork) english_text feathers feral hi_res humor
lol_comments oral oral_penetration penetration solo swish talons text wings
url: https://static1.e621.net/data/7c/d9/7cd90352fa57ddaeb3f422de355e727c.jpg
- tags: 2017 5_fingers alternate_form anthro canid canine clothed clothing cup cups_on_ears
cute_fangs dagger detailed_background dialogue digital_media_(artwork) dutch_angle
english_text fox fur gregg_(nitw) happy inside jacket knife koul looking_at_viewer
male mammal melee_weapon night_in_the_woods open_mouth orange_fur smile solo speech_bubble
text video_games weapon
url: https://static1.e621.net/data/4f/be/4fbe36ed49bf8d501edb8509a554837d.jpg
- tags: ambiguous_gender canid canine conditional_dnp daww derp_eyes digital_media_(artwork)
digital_painting_(artwork) ears_back eyes_closed feral flexible fluffy fox full-length_portrait
fur humor lol_comments mammal markings oops orange_fur paws playing portrait red_fox
side_view simple_background snow socks_(marking) solo trunchbull upside_down whiskers
white_background white_fur
url: https://static1.e621.net/data/94/d1/94d108d2e4ed476a113f93e7768accce.jpg
- tags: anthro canid canine clothed clothing english_text fangs female fur hair image_macro
impact_(font) jurassic_park mammal meme nasusbot open_mouth parody profanity reaction_image
skrillex smile solo teeth text
url: https://static1.e621.net/data/cb/a4/cba428d3227dd7358dbf63787c759e8d.png
- tags: "<3 3_toes ambiguous_gender anthro barefoot biped black_fur black_markings
blue_fur blue_tail blush canid canine cel_shading cheek_tuft collar digital_media_(artwork)
digitigrade facial_markings feet fur fur_tuft gloves_(marking) gradient_background
kneeling leash leash_in_mouth lucario mammal markings mouth_hold multicolored_fur
neck_tuft nintendo nude object_in_mouth paws pink_background pokémon pokémon_(species)
pseudo_clothing rakkuguy red_eyes shaded side_view simple_background smile snout
solo spikes submissive toes tuft video_games white_background yellow_fur"
url: https://static1.e621.net/data/a1/1e/a11e49bd7c556049770b3e905e9528ef.png
- tags: 2013 4_fingers anthro barefoot beverage black_fur black_nose canid canine
clothed clothing coffee coffee_mug cup dipstick_ears dipstick_tail english_text
eyes_closed fennec fingerless_(marking) fluffy fluffy_tail food fox fully_clothed
fur gloves_(marking) hair hi_res inner_ear_fluff lying male mammal markings multicolored_tail
orange_fur orange_hair pants reaching shirt side_view simple_background sleeping
socks_(marking) solo sound_effects text thanshuhai tired toeless_(marking) tongue
tongue_out white_background white_fur zzz
url: https://static1.e621.net/data/8d/eb/8deb2ae9fe81f9f6383a24c591bdd3be.png
- tags: 2016 alolan_vulpix altered_reflection ambiguous_gender black_nose brown_eyes
brown_hair canid canine contrast digital_media_(artwork) duality feral fur grey_nose
hair hindpaw hi_res inner_ear_fluff looking_at_viewer mammal multi_tail nintendo
paws pokémon pokémon_(species) realistic reflection regional_variant solo split_screen
standing symmetry tamberella tan_fur video_games vulpix white_fur
url: https://static1.e621.net/data/7e/11/7e11e929a5c5b58078d600d3aa23cf21.jpg
- tags: anthro canid canine clothed clothing disney edit english_text fox fully_clothed
gradient_background lyrics male mammal michael_jackson music nick_wilde simple_background
smile smooth_criminal solo song sound text zootopia 羽默空_(artist)
url: https://static1.e621.net/data/fc/09/fc090f0332c2ae9e91bb6953179bceaf.jpg
- tags: anthro antlers brown_fur cellphone cervid cloud duo felid fur green_eyes hi_res
horn humor imminent_death lion male mammal nbowa outside pantherine phone predator/prey
pretending selfie sky tirrel tirrel_(character) tongue tongue_out tree
url: https://static1.e621.net/data/d9/0e/d90ea5d58bbb37f6c08d054946a478f9.jpg
- tags: 2016 anthro black_fur black_hair black_nose blizzard_entertainment bound breasts
canid canine cheek_tuft conditional_dnp crying digital_media_(artwork) domestic_cat
dream_eater duo e621 english_text eyelashes fan_character felid feline felis female
feral floof flora_fauna fluffy food food_creature fruit fur green_eyes hair hi_res
horn humor impact_(font) kingdom_hearts lol_comments looking_up mammal melon meloncat
melonyan meme meow_wow meta nude paralee_(character) plant poof profanity rainbow
ratte sad square_enix tardar_sauce tears technicolor_yawn text tuft video_games
vomit wall_of_text warcraft watermelon were werecanid werecanine werewolf worgen
url: https://static1.e621.net/data/42/2a/422aaf2c210d6e0e48480ce419b06896.png
- tags: 2016 <3 4_fingers abstract_background anthro asriel_dreemurr big_eyes black_background
blush boss_monster bovid braeburned brown_background caprine cheek_tuft clothing
cute_fangs digital_media_(artwork) fangs feels fur gesture goat gradient_background
green_clothing green_topwear hair half-length_portrait hand_heart head_tuft hi_res
long_ears looking_at_viewer love male mammal multicolored_clothing open_mouth
pink_tongue portrait sharp_teeth signature simple_background smile solo sweater
teeth tongue tuft undertale video_games white_fur yellow_bottomwear yellow_clothing
young
url: https://static1.e621.net/data/14/e7/14e7eff45c61ba29e02f4f59846dc6bc.png
- tags: "... <3 absurd_res ambiguous_gender beady_eyes blep dialogue english_text
feral forked_tongue hi_res iron_and_whine python reptile scalie simple_background
snake solo text tongue tongue_out traditional_media_(artwork) white_background"
url: https://static1.e621.net/data/7f/6a/7f6af5deef179238510cfa1d606ef81f.jpg
- tags: 2016 alantka anthro canid canine cuddling detailed_background disney duo embrace
eyes_closed female forest fox fur gloves_(marking) green_eyes grey_fur judy_hopps
lagomorph long_ears looking_down male mammal markings nick_wilde orange_fur outside
predator/prey rabbit romantic_couple size_difference smile style_parody tree zootopia
url: https://static1.e621.net/data/e1/28/e128617350d9e02bf816f0d4d529c210.jpg
- tags: 2016 absurd_res anthro barefoot bed bedroom bracelet buckteeth canid canine
choker dancing dennyvixen dipstick_tail disney duo earbuds eyes_closed female
fox fur gloves_(marking) good_morning grey_fur happy headphones hi_res inner_ear_fluff
inside ipod ipod_nano jewelry judy_hopps lagomorph long_ears male mammal markings
multicolored_tail nick_wilde on_bed open_mouth orange_fur pawpads portable_music_player
predator/prey rabbit smile teeth two_tone_tail upscale zootopia
url: https://static1.e621.net/data/2e/d4/2ed4a63c7105f9e6ca099033403b242a.png
- tags: ">.< :< :> :| •≠• :3 ambiguous_gender black_eyes :d d: expressions food_creature
frown group humor looking_at_viewer low_res mint not_furry :o o3o open_mouth plastic
real smile tic_tac tongue tongue_out w4nw4n x_x"
url: https://static1.e621.net/data/e5/1e/e51edfb8ec608817cca55d9bf7579c47.jpg
- tags: absurd_res anthro bed bouquet canid canine canis clothing duo eyes_closed
female flower_bouquet hair hi_res human larger_anthro larger_female male mammal
size_difference sleeping smaller_human smaller_male spooning vanchamarl were werecanid
werecanine werewolf wholesome wolf zephra
url: https://static1.e621.net/data/14/b5/14b5352ee09a0dee5a565f5c0e6bfb3c.png
- tags: 2016 anthro blue_eyes boss_monster bovid caprine cellphone crossover disney
english_text female fur goat holding_object horn image_macro long_ears mammal
meme monsters_inc open_mouth parody phone pixar reaction_image solo sulley taken_(movie)
text toriel undertale video_games white_fur wolfjedisamuel
url: https://static1.e621.net/data/fb/52/fb52b8b36ecb85eaf155855a23e70f24.png
- tags: animated anthro asriel_dreemurr blush boss_monster bovid caprine clothing
computer edit empty_eyes english_text floppy_ears goat happy hyperactive lol_comments
male mammal o_o simple_background smile solo text undertale undertale-tales video_games
url: https://static1.e621.net/data/bf/3c/bf3ce93ea4f3e7e3719c59b6557343b0.gif
- tags: 2016 angry anthro antlers bell cervid collar computer furry_problems green_eyes
horn laptop lol_comments male mammal reaction_image solo tirrel tirrel_(character)
url: https://static1.e621.net/data/9c/39/9c39de16aa06ea3afbc0ca4cd3137960.jpg
- tags: anthro big_breasts black_fur black_nose blue_eyes breasts claws clothed clothing
english_text female fur giant_panda gillpanda gillpanda_(character) looking_at_viewer
mammal morbidly_obese motivational_poster multicolored_fur obese overweight overweight_female
pawpads pen sharp_teeth simple_background smile solo teeth text thumbs_up two_tone_fur
ursid white_background white_fur
url: https://static1.e621.net/data/fa/67/fa67485134b0ee19fdaa49a68161f4f5.jpg
- tags: 2015 anthro asriel_dreemurr big_eyes boss_monster bovid caprine clothed clothing
fangs fatz_geronimo goat hoodie horn long_ears male mammal purple_background reaction_image
simple_background solo undertale video_games wide_eyed
url: https://static1.e621.net/data/f1/8d/f18db1184cf4c62d7afbdf8fd28f39f7.png
- tags: 2015 anatomy anthro asriel_dreemurr boss_monster bovid bukoya-star caprine
chart child clothed clothing cub english_text flower fur goat green_eyes grey_background
hi_res long_ears looking_at_viewer male mammal open_mouth plant simple_background
solo text undertale video_games white_fur young
url: https://static1.e621.net/data/b6/33/b633e381a700c619f7ea22666cf6b93d.jpg
- tags: 2015 <3 anthro asriel_dreemurr_(god_form) blue_background boss_monster bovid
caprine clothed clothing digital_media_(artwork) eating fluffy_hair fur gem goat
hair horn looking_at_viewer male mammal pocky red_eyes robe saturnspace simple_background
solo undertale video_games white_fur white_hair
url: https://static1.e621.net/data/8b/80/8b8000f1845841e50515eb0aa224abfb.png
- tags: 2015 ambiguous_gender baseball_cap beady_eyes black_eyes digital_media_(artwork)
feral forked_tongue grey_tongue half-length_portrait hat lol_comments meme mostly_nude
portrait purple_headwear python reptile scalie simple_background smile snake solo
tongue tongue_out unknown_artist white_background
url: https://static1.e621.net/data/bf/f6/bff630817262325b514eee7ff197802e.png
- tags: 2015 ambiguous_gender avian beak bird bread cere_(feature) columbid common_pigeon
crumbs cryptid-creations derp_eyes doing_it_wrong feathers feral flour folded_wings
food humor in_bread lol_comments meme pigeon red_eyes simple_background solo watermark
what white_background
url: https://static1.e621.net/data/f9/1f/f91f92ac563c3bbe4e569d68a46dfafe.png
- tags: 2015 ambiguous_gender anthro blue_eyes clothing cosplay costume day detailed_background
dragon dreamworks falvie fudge_the_otter how_to_train_your_dragon kigurumi mammal
membranous_wings mustelid night_fury open_mouth otter outside sitting sky smile
solo star starry_sky sunset toothless wings
url: https://static1.e621.net/data/0f/d1/0fd1d92190633265fb32a800d65c82d7.png
- tags: 2015 5_fingers ambiguous_gender anthro black_lips black_nose canid canine
canis controller domestic_cat duo eye_contact felid feline felis fluffy fluffy_tail
fur grey_fur handpaw hax_(artist) inside jackal kenket lamp lofi long_mouth looking_at_another
looking_down looking_up lying mammal no_sclera nude on_back orange_eyes pawpads
paws pink_nose reaching remote_control romantic_couple shaded side_view slice_of_life
smile snout sofa table tv_remote whiskers white_fur yellow_eyes
url: https://static1.e621.net/data/0c/09/0c09080148c52ed89f16fe8fbc731dcf.jpg
- tags: 2012 anthro beverage black_fur building cafe camera_view canid canine car
chair cheek_tuft clothed clothing coffee coffee_mug coffee_shop cup detailed_background
digital_media_(artwork) eyebrows fog food fox fur green_eyes hair half-length_portrait
high-angle_view inside looking_at_viewer male mammal multicolored_fur orange_fur
orange_hair portrait red_fox selfie sitting slice_of_life smile solo table thanshuhai
tuft vehicle white_fur
url: https://static1.e621.net/data/a0/47/a0476a240b0b780b926d831a3e6426ea.png
- tags: angry blue_body blue_eyes blue_hair blush dialogue english_text equine eyelashes
eyes_closed female friendship_is_magic hair horn horse humor long_hair mammal
my_little_pony open_mouth orange_background pink_tongue princess_luna_(mlp) profanity
reaction_image simple_background solo sweat teeth text the_truth tongue unknown_artist
winged_unicorn wings
url: https://static1.e621.net/data/ef/e5/efe507d244c5841d8496ce52f4f706a6.png
- tags: "... ambiguous_gender bed bedding black_fur blanket checkered_background domestic_cat
english_text felid feline felis female fur garfield_(series) lying mae_(nitw)
mammal night_in_the_woods on_bed on_front pattern_background reaction_image simple_background
solo speech_bubble text under_covers unknown_artist video_games"
url: https://static1.e621.net/data/19/43/194344f13372ea3e80ef007dd56463c2.png
- tags: 2015 anthro cheetah clothed clothing detailed_background felid feline female
flashlight fully_clothed gun handgun holding_object mammal menacing muscular muscular_female
outside pistol police ranged_weapon solo standing street_lamp sunrise tirrel uniform
weapon yellow_sclera
url: https://static1.e621.net/data/d3/ae/d3aee9d4de485f2be935e84ebbd971b7.jpg
- tags: 2015 anthro antlers bell blue_eyes brown_hair canid canine car cervid cheetah
clothed clothing collar comic dialogue driver driving duo english_text felid feline
female green_eyes hair hat headlight hi_res horn humor inside_car male mammal
outside police profanity running text tirrel tirrel_(character) uniform vehicle
url: https://static1.e621.net/data/ed/e7/ede74f19c7adc6115fb751d729eceaf8.jpg
- tags: 2013 ambiguous_gender angry brown_fur canid canine chibi dipstick_tail english_text
feral fox fur humor mammal markings multicolored_fur multicolored_tail orange_fur
profanity running serious simple_background socks_(marking) solo technicolorpie
technicolor_pie text two_tone_tail white_background white_fur yellow_fur
url: https://static1.e621.net/data/44/53/4453fcdd6d4ce1cf6d6da88c9a35bafc.png
- tags: 2013 abstract_background ambiguous_gender anthro arm_support blonde_hair bow_tie
bust_portrait clothed clothing coat cosplay digital_media_(artwork) felid fur
gene_wilder hair half-closed_eyes hat humor inner_ear_fluff leaning_on_elbow lol_comments
long_hair low_res mammal meme pantherine parody portrait reaction_image smile
solo tassy tiger top_hat willy_wonka willy_wonka_and_the_chocolate_factory yellow_eyes
yellow_fur
url: https://static1.e621.net/data/d1/bb/d1bbf569513c5acf13b1be36d1d64bff.png
- tags: begging begging_pose blue_fur blue_tail canid canine chest_tuft conditional_dnp
dipstick_tail facial_markings fan_character feral feralized fluffy fur looking_away
male mammal markings mask_(marking) multicolored_fur multicolored_tail nintendo
pokémon pokémon_(species) portrait red_eyes riolu simple_background smile solo
tuft two_tone_fur two_tone_tail umpherio_(umpherio) video_games white_background
white_fur white_tail xnirox
url: https://static1.e621.net/data/97/38/973887346d669d97c7a75b7324855773.png
- tags: 2014 <3 anthro avian beak bird black_eyes black_nose blue_body blue_feathers
blue_jay blush brown_fur cartoon_network chest_tuft comic corvid dialogue duo
english_text eyes_closed fangs feathers fur grey_beak hi_res kissing kissing_cheek
love male male/male mammal markings mordecai_(regular_show) open_beak open_mouth
procyonid raccoon regular_show rigby_(regular_show) romantic_couple simple_background
stripes surprise tan_fur teeth text tongue tuft white_background white_body white_feathers
wholesome xiamtheferret
url: https://static1.e621.net/data/ca/c9/cac98850f5b5b48440c100ad800caac1.png
- tags: anthro blonde_hair blue_eyes bone_necklace breasts carnivore clothed clothing
digital_media_(artwork) domestic_cat eating eyebrows felid feline felis female
food front_view hair half-length_portrait holding_food holding_object inuki inuki_(character)
jewelry mammal meat melloque necklace pink_nose ponytail portrait shirt shirt_logo
signature simple_background smile solo steak teeth
url: https://static1.e621.net/data/63/43/63433706609c428f2027986940547834.png
- tags: 2015 applejack_(mlp) blonde_hair cutie_mark earth_pony equine face_paint feathers
female feral friendship_is_magic green_eyes hair headdress hi_res horse jewelry
looking_at_viewer mammal my_little_pony native_american necklace pony portrait
santagiera solo teeth
url: https://static1.e621.net/data/ac/85/ac85e5ea07ae712946bb897bff734d59.jpg
- tags: 2015 animatronic anthro avian beak beverage bird blue_eyes blush bonnie_(fnaf)
canid canine cellphone chica_(fnaf) chicken eye_patch eyewear five_nights_at_freddy's
food fox foxy_(fnaf) freddy_(fnaf) group happy hat humor kissing lagomorph laugh
looking_away machine male male/male mammal phone purple_eyes rabbit robot smile
spin_the_bottle ursid video_games xiamtheferret yellow_eyes
url: https://static1.e621.net/data/be/55/be5581393bcf2451ca90c16ba48c694c.png
- tags: 2014 anthro antiander blue_eyes canid canine clothed clothing dress feathered_wings
feathers female fox gloves hair heterochromia hi_res holly_(plant) long_hair mammal
plant solo source_request white_hair wings
url: https://static1.e621.net/data/7c/8a/7c8a07df68f6b8c93d425158396df811.png
- tags: 2012 ambiguous_gender black_fur black_nose eeveelution fadingsky feral fire
fur markings nintendo pink_background pokémon pokémon_(species) red_eyes simple_background
smoke solo umbreon video_games yellow_markings
url: https://static1.e621.net/data/d8/2f/d82fc9c3bfa78c17db4d117950063124.png
- tags: 2014 ass_up avian beak blue_eyes blue_fur braeburned digital_media_(artwork)
earth_pony equine feathered_wings feathers female feral friendship_is_magic fur
gilda_(mlp) group gryphon hair horse laser laser_pointer mammal multicolored_hair
my_little_pony pegasus pink_fur pink_hair pinkie_pie_(mlp) pony purple_eyes rainbow_dash_(mlp)
rainbow_hair tongue tongue_out wings yellow_eyes
url: https://static1.e621.net/data/8c/08/8c08e77a944dd6df29eb3e908f5bd93f.png
- tags: ambiguous_gender anthro bust_portrait canid canine canis close-up darkwingo
dingo eye_reflection fluffy green_background green_eyes head_tilt hi_res hybrid
jewelry mammal markings necklace portrait scar simple_background smile solo thanshuhai
wolf
url: https://static1.e621.net/data/d7/10/d710ff227b96e59a655d152ac2fcc9f7.jpg
- tags: 2014 <3 anthro beverage beverage_can black_hair blue_hair blue_highlights
clothing collar digital_media_(artwork) domestic_cat fangs felid feline felis
female food gradient_hair green_eyes hair highlights jacket looking_at_viewer
mammal smile solo tentacletongue wolfy-nail young
url: https://static1.e621.net/data/86/94/86942ce7f5be8ba952fef914c5593d2e.jpg
- tags: 2012 ambiguous_gender bed bedding blanket blue_eyes eeveelution feral hi_res
looking_at_viewer lying nintendo on_bed on_front open_mouth pawpads pokémon pokémon_(species)
shadow solo tartii under_covers vaporeon video_games watermark
url: https://static1.e621.net/data/c0/d4/c0d4964ebc0fb0eeddb61bc03cbc6a2b.jpg
- tags: 2014 5:4 anthro atryl avian beak black_feathers brown_feathers cloud digital_media_(artwork)
duo eye_contact feathered_wings feathers female friendship_is_magic genevieve_(mlp)
grass greta_(mlp) grey_eyes gryphon hug my_little_pony one_eye_closed outside
sky smile white_feathers wings wink
url: https://static1.e621.net/data/67/c9/67c952de260ede67d0fe507bb99d3a6e.png
- tags: 2014 3_toes ambiguous_gender animated anthro ass_up black_scales butt digitigrade
dragon felid feral group hindpaw humor inside_train lamp loop low_res male mammal
membranous_wings metro multicolored_scales paws pushing rubble scales scalie size_difference
solo_focus subway tirrel toes train tunnel two_tone_scales vehicle white_scales
wings
url: https://static1.e621.net/data/7d/0d/7d0de8443bad63b6bd56a24ca0d0fb98.gif

View File

@ -1,14 +1,14 @@
#!/usr/bin/env ruby
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment'))
ModAction.find_each do |p|
begin
p.values = p.values_old
p.save!(validate: false)
rescue Encoding::UndefinedConversionError => e
# Interacting with the model at all throws the exception again. Yay rails.
rescue => e
puts "#{p.id} has an exception"
end
end
#!/usr/bin/env ruby
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment'))
ModAction.find_each do |p|
begin
p.values = p.values_old
p.save!(validate: false)
rescue Encoding::UndefinedConversionError => e
# Interacting with the model at all throws the exception again. Yay rails.
rescue => e
puts "#{p.id} has an exception"
end
end

View File

@ -1,4 +1,4 @@
FactoryBot.define do
factory(:upload_whitelist) do
end
end
FactoryBot.define do
factory(:upload_whitelist) do
end
end

View File

@ -24,4 +24,4 @@ module Maintenance
end
end
end
end
end

View File

@ -36,4 +36,4 @@ module Maintenance
end
end
end
end
end