forked from e621ng/e621ng
Normalize EOL style + newline at end of files.
This commit is contained in:
parent
77328c75a8
commit
db8d4c4773
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -1,3 +1,3 @@
|
||||
@function border_color($color) {
|
||||
@return darken($color, 25%);
|
||||
}
|
||||
@function border_color($color) {
|
||||
@return darken($color, 25%);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -2,4 +2,4 @@
|
||||
.section {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,4 +2,4 @@ div#c-maintenance-user-login-reminders {
|
||||
div#a-new {
|
||||
width: 50em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,4 +2,4 @@
|
||||
section {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,4 +7,4 @@ div#c-maintenance-user-deletions {
|
||||
li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -36,4 +36,4 @@ module Danbooru
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Sources
|
||||
module Alternates
|
||||
class Null < Base
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
module Sources
|
||||
module Alternates
|
||||
class Null < Base
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -15,4 +15,4 @@ class PostReportReason < ApplicationRecord
|
||||
reasons.each {|x| js_map[x.id] = x.description}
|
||||
js_map
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -0,0 +1 @@
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 %>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 %>
|
||||
|
@ -1 +1 @@
|
||||
<%= render "iqdb_queries/matches" %>
|
||||
<%= render "iqdb_queries/matches" %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -1 +1 @@
|
||||
<%= raw @results[:sums].to_json %>
|
||||
<%= raw @results[:sums].to_json %>
|
||||
|
@ -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" %>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -0,0 +1 @@
|
||||
|
@ -1,2 +1,2 @@
|
||||
<h1>Too Many Requests</h1>
|
||||
<p>Please rate limit yourself</p>
|
||||
<p>Please rate limit yourself</p>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 %>
|
||||
|
@ -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' %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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>
|
||||
|
@ -0,0 +1 @@
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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>
|
||||
|
@ -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 %>
|
||||
|
@ -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 %>
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -67,4 +67,4 @@ services:
|
||||
- db
|
||||
- memcached
|
||||
- archives
|
||||
- redis
|
||||
- redis
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
Elasticsearch::Model.client = Elasticsearch::Client.new host: Danbooru.config.elasticsearch_host
|
||||
Elasticsearch::Model.client = Elasticsearch::Client.new host: Danbooru.config.elasticsearch_host
|
||||
|
@ -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
|
||||
|
@ -61,4 +61,4 @@ if Rails.env.test?
|
||||
alias_method :fetch_without_retry, :fetch
|
||||
alias_method :fetch, :fetch_with_retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1 +1 @@
|
||||
ActiveModelSerializers.config.adapter = :json
|
||||
ActiveModelSerializers.config.adapter = :json
|
||||
|
@ -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
|
||||
|
@ -23,4 +23,4 @@ production:
|
||||
|
||||
staging:
|
||||
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
||||
|
||||
|
||||
|
@ -44,4 +44,4 @@ after_fork do |server, worker|
|
||||
if defined?(ActiveRecord::Base)
|
||||
ActiveRecord::Base.establish_connection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
892
db/seeds.yml
892
db/seeds.yml
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
FactoryBot.define do
|
||||
factory(:upload_whitelist) do
|
||||
end
|
||||
end
|
||||
FactoryBot.define do
|
||||
factory(:upload_whitelist) do
|
||||
end
|
||||
end
|
||||
|
@ -24,4 +24,4 @@ module Maintenance
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -36,4 +36,4 @@ module Maintenance
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user