add "change hole" button
parent
15fa096105
commit
7bada8f70e
|
@ -0,0 +1,36 @@
|
|||
const hole_to = document.getElementById("hole_to")
|
||||
const changeHoleButton = document.getElementById("changeHoleButton");
|
||||
|
||||
hole_to.addEventListener('keydown', (e) => {
|
||||
if (!((e.ctrlKey || e.metaKey) && e.key === "Enter")) return;
|
||||
|
||||
const targetDOM = document.activeElement;
|
||||
if (!(targetDOM instanceof HTMLInputElement)) return;
|
||||
|
||||
changeHoleButton.click()
|
||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('changeHoleModal')).hide()
|
||||
});
|
||||
|
||||
function change_holeModal(id) {
|
||||
changeHoleButton.disabled = false;
|
||||
changeHoleButton.classList.remove('disabled');
|
||||
changeHoleButton.innerHTML='Change Hole';
|
||||
changeHoleButton.dataset.id = id
|
||||
|
||||
hole_to.value = ""
|
||||
setTimeout(() => {
|
||||
hole_to.focus()
|
||||
}, 500);
|
||||
};
|
||||
|
||||
changeHoleButton.onclick = function() {
|
||||
this.disabled = true;
|
||||
this.classList.add('disabled');
|
||||
|
||||
postToast(this, '/change_hole/' + changeHoleButton.dataset.id,
|
||||
{
|
||||
"hole_to": hole_to.value
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
}
|
|
@ -24,7 +24,6 @@ function report_postModal(id) {
|
|||
};
|
||||
|
||||
reportPostButton.onclick = function() {
|
||||
this.innerHTML='Reporting post';
|
||||
this.disabled = true;
|
||||
this.classList.add('disabled');
|
||||
|
||||
|
|
|
@ -414,3 +414,10 @@ class Post(Base):
|
|||
@lazy
|
||||
def is_longpost(self):
|
||||
return len(self.body) >= 2000
|
||||
|
||||
@lazy
|
||||
def hole_changable(self, v):
|
||||
if self.hole == 'chudrama':
|
||||
return v.admin_level >= PERMS['POST_COMMENT_MODERATION']
|
||||
else:
|
||||
return v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (self.hole and v.mods_hole(hole_from)) or self.author_id == v.id
|
||||
|
|
|
@ -24,7 +24,7 @@ HOLEACTION_TYPES = {
|
|||
"icon": 'fa-feather-alt',
|
||||
"color": 'bg-danger'
|
||||
},
|
||||
'move_hole': {
|
||||
'change_hole': {
|
||||
"str": 'changed hole of {self.target_link}',
|
||||
"icon": 'fa-manhole',
|
||||
"color": 'bg-primary'
|
||||
|
|
|
@ -216,7 +216,7 @@ MODACTION_TYPES = {
|
|||
"icon": 'fa-memo',
|
||||
"color": 'bg-danger'
|
||||
},
|
||||
'move_hole': {
|
||||
'change_hole': {
|
||||
"str": 'changed hole of {self.target_link}',
|
||||
"icon": 'fa-manhole',
|
||||
"color": 'bg-primary'
|
||||
|
|
|
@ -1005,3 +1005,98 @@ def post_hole_snappy_quotes(v, hole):
|
|||
g.db.add(ma)
|
||||
|
||||
return {"message": "Snappy quotes edited successfully!"}
|
||||
|
||||
|
||||
@app.post("/change_hole/<int:pid>")
|
||||
@limiter.limit('1/second', scope=rpath)
|
||||
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
||||
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
|
||||
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
||||
@auth_required
|
||||
def change_hole(pid, v):
|
||||
post = get_post(pid)
|
||||
|
||||
if post.ghost:
|
||||
abort(403, "You can't move ghost posts into holes!")
|
||||
|
||||
hole_from = post.hole
|
||||
|
||||
hole_to = request.values.get("hole_to", "").strip()
|
||||
hole_to = get_hole(hole_to, graceful=True)
|
||||
hole_to = hole_to.name if hole_to else None
|
||||
|
||||
if not post.hole_changable(v):
|
||||
return False
|
||||
|
||||
if hole_to == None:
|
||||
if HOLE_REQUIRED:
|
||||
abort(403, "All posts are required to be in holes!")
|
||||
hole_to_in_notif = 'the main feed'
|
||||
else:
|
||||
hole_to_in_notif = f'/h/{hole_to}'
|
||||
|
||||
if hole_from == hole_to:
|
||||
abort(409, f"Post is already in {hole_to_in_notif}")
|
||||
|
||||
if post.author.exiler_username(hole_to):
|
||||
abort(403, f"User is exiled from this hole!")
|
||||
|
||||
if hole_to == 'changelog':
|
||||
abort(403, "/h/changelog is archived!")
|
||||
|
||||
if hole_to in {'furry','vampire','racist','femboy','edgy'} and not v.client and not post.author.house.lower().startswith(hole_to):
|
||||
if v.id == post.author_id:
|
||||
abort(403, f"You need to be a member of House {hole_to.capitalize()} to post in /h/{hole_to}")
|
||||
else:
|
||||
abort(403, f"@{post.author_name} needs to be a member of House {hole_to.capitalize()} for their post to be moved to /h/{hole_to}")
|
||||
|
||||
post.hole = hole_to
|
||||
post.hole_pinned = None
|
||||
|
||||
if hole_to == 'chudrama':
|
||||
post.bannedfor = None
|
||||
post.chuddedfor = None
|
||||
for c in post.comments:
|
||||
c.bannedfor = None
|
||||
c.chuddedfor = None
|
||||
g.db.add(c)
|
||||
|
||||
g.db.add(post)
|
||||
|
||||
if v.id != post.author_id:
|
||||
hole_from_str = 'main feed' if hole_from is None else \
|
||||
f'<a href="/h/{hole_from}">/h/{hole_from}</a>'
|
||||
hole_to_str = 'main feed' if hole_to is None else \
|
||||
f'<a href="/h/{hole_to}">/h/{hole_to}</a>'
|
||||
|
||||
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
|
||||
ma = ModAction(
|
||||
kind='change_hole',
|
||||
user_id=v.id,
|
||||
target_post_id=post.id,
|
||||
_note=f'{hole_from_str} → {hole_to_str}',
|
||||
)
|
||||
g.db.add(ma)
|
||||
position = 'a site admin'
|
||||
else:
|
||||
ma = HoleAction(
|
||||
hole=hole_from,
|
||||
kind='change_hole',
|
||||
user_id=v.id,
|
||||
target_post_id=post.id,
|
||||
_note=f'{hole_from_str} → {hole_to_str}',
|
||||
)
|
||||
g.db.add(ma)
|
||||
position = f'a /h/{hole_from} mod'
|
||||
|
||||
if hole_from == None:
|
||||
hole_from_in_notif = 'the main feed'
|
||||
else:
|
||||
hole_from_in_notif = f'/h/{hole_from}'
|
||||
|
||||
message = f"@{v.username} ({position}) has moved [{post.title}]({post.shortlink}) from {hole_from_in_notif} to {hole_to_in_notif}"
|
||||
send_repeatable_notification(post.author_id, message)
|
||||
|
||||
cache.delete_memoized(frontlist)
|
||||
|
||||
return {"message": f"Post moved to {hole_to_in_notif} successfully!"}
|
||||
|
|
|
@ -150,6 +150,15 @@ def poster_of_the_day():
|
|||
user = g.db.query(User).filter_by(id=uid).one()
|
||||
return user
|
||||
|
||||
|
||||
def HOLES():
|
||||
HOLES = [x[0] for x in g.db.query(Hole.name).order_by(Hole.name)]
|
||||
if "other" in HOLES:
|
||||
HOLES.remove("other")
|
||||
HOLES.append("other")
|
||||
return HOLES
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def inject_constants():
|
||||
return {
|
||||
|
@ -177,7 +186,7 @@ def inject_constants():
|
|||
"SITE_FULL_IMAGES": SITE_FULL_IMAGES,
|
||||
"IS_EVENT":IS_EVENT, "IS_FISTMAS":IS_FISTMAS, "IS_HOMOWEEN":IS_HOMOWEEN,
|
||||
"IS_DKD":IS_DKD, "IS_BIRTHGAY":IS_BIRTHGAY, "IS_BIRTHDEAD":IS_BIRTHDEAD,
|
||||
"CHUD_PHRASES":CHUD_PHRASES, "hasattr":hasattr, "calc_users":calc_users, "HOLE_INACTIVITY_DELETION":HOLE_INACTIVITY_DELETION, "LIGHT_THEMES":LIGHT_THEMES, "NSFW_EMOJIS":NSFW_EMOJIS,
|
||||
"CHUD_PHRASES":CHUD_PHRASES, "hasattr":hasattr, "calc_users":calc_users, "HOLE_INACTIVITY_DELETION":HOLE_INACTIVITY_DELETION, "LIGHT_THEMES":LIGHT_THEMES, "NSFW_EMOJIS":NSFW_EMOJIS, "HOLES":HOLES,
|
||||
"MAX_IMAGE_AUDIO_SIZE_MB":MAX_IMAGE_AUDIO_SIZE_MB, "MAX_IMAGE_AUDIO_SIZE_MB_PATRON":MAX_IMAGE_AUDIO_SIZE_MB_PATRON,
|
||||
"MAX_VIDEO_SIZE_MB":MAX_VIDEO_SIZE_MB, "MAX_VIDEO_SIZE_MB_PATRON":MAX_VIDEO_SIZE_MB_PATRON,
|
||||
"CURSORMARSEY_DEFAULT":CURSORMARSEY_DEFAULT, "SNAPPY_ID":SNAPPY_ID, "get_running_orgy":get_running_orgy,
|
||||
|
|
|
@ -96,15 +96,10 @@ def publish(pid, v):
|
|||
@auth_required
|
||||
def submit_get(v, hole=None):
|
||||
hole = get_hole(hole, graceful=True)
|
||||
|
||||
if request.path.startswith('/h/') and not hole: abort(404)
|
||||
|
||||
HOLES = [x[0] for x in g.db.query(Hole.name).order_by(Hole.name)]
|
||||
|
||||
if "other" in HOLES:
|
||||
HOLES.remove("other")
|
||||
HOLES.append("other")
|
||||
|
||||
return render_template("submit.html", HOLES=HOLES, v=v, hole=hole)
|
||||
return render_template("submit.html", v=v, hole=hole)
|
||||
|
||||
@app.get("/post/<int:pid>")
|
||||
@app.get("/post/<int:pid>/<anything>")
|
||||
|
|
|
@ -60,9 +60,6 @@ def report_post(pid, v):
|
|||
|
||||
return {"message": "Post flaired successfully!"}
|
||||
|
||||
moved = move_post(post, v, reason)
|
||||
if moved: return {"message": moved}
|
||||
|
||||
if v.is_muted: abort(403, "You are forbidden from making reports!")
|
||||
|
||||
existing = g.db.query(Report.post_id).filter_by(user_id=v.id, post_id=post.id).one_or_none()
|
||||
|
@ -162,91 +159,3 @@ def remove_report_comment(v, cid, uid):
|
|||
g.db.add(ma)
|
||||
|
||||
return {"message": "Report removed successfully!"}
|
||||
|
||||
def move_post(post, v, reason):
|
||||
if not reason.startswith('/h/') and not reason.startswith('h/'):
|
||||
return False
|
||||
|
||||
if post.ghost:
|
||||
abort(403, "You can't move ghost posts into holes!")
|
||||
|
||||
hole_from = post.hole
|
||||
hole_to = get_hole(reason, graceful=True)
|
||||
hole_to = hole_to.name if hole_to else None
|
||||
|
||||
can_move_post = v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (post.hole and v.mods_hole(hole_from))
|
||||
if hole_from != 'chudrama': # posts can only be moved out of /h/chudrama by admins
|
||||
can_move_post = can_move_post or post.author_id == v.id
|
||||
if not can_move_post: return False
|
||||
|
||||
if hole_to == None:
|
||||
if HOLE_REQUIRED:
|
||||
abort(403, "All posts are required to be flaired!")
|
||||
hole_to_in_notif = 'the main feed'
|
||||
else:
|
||||
hole_to_in_notif = f'/h/{hole_to}'
|
||||
|
||||
if hole_from == hole_to: abort(409, f"Post is already in {hole_to_in_notif}")
|
||||
|
||||
if post.author.exiler_username(hole_to):
|
||||
abort(403, f"User is exiled from this hole!")
|
||||
|
||||
if hole_to == 'changelog':
|
||||
abort(403, "/h/changelog is archived!")
|
||||
|
||||
if hole_to in {'furry','vampire','racist','femboy','edgy'} and not v.client and not post.author.house.lower().startswith(hole_to):
|
||||
if v.id == post.author_id:
|
||||
abort(403, f"You need to be a member of House {hole_to.capitalize()} to post in /h/{hole_to}")
|
||||
else:
|
||||
abort(403, f"@{post.author_name} needs to be a member of House {hole_to.capitalize()} for their post to be moved to /h/{hole_to}")
|
||||
|
||||
post.hole = hole_to
|
||||
post.hole_pinned = None
|
||||
|
||||
if hole_to == 'chudrama':
|
||||
post.bannedfor = None
|
||||
post.chuddedfor = None
|
||||
for c in post.comments:
|
||||
c.bannedfor = None
|
||||
c.chuddedfor = None
|
||||
g.db.add(c)
|
||||
|
||||
g.db.add(post)
|
||||
|
||||
if v.id != post.author_id:
|
||||
hole_from_str = 'main feed' if hole_from is None else \
|
||||
f'<a href="/h/{hole_from}">/h/{hole_from}</a>'
|
||||
hole_to_str = 'main feed' if hole_to is None else \
|
||||
f'<a href="/h/{hole_to}">/h/{hole_to}</a>'
|
||||
|
||||
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
|
||||
ma = ModAction(
|
||||
kind='move_hole',
|
||||
user_id=v.id,
|
||||
target_post_id=post.id,
|
||||
_note=f'{hole_from_str} → {hole_to_str}',
|
||||
)
|
||||
g.db.add(ma)
|
||||
position = 'a site admin'
|
||||
else:
|
||||
ma = HoleAction(
|
||||
hole=hole_from,
|
||||
kind='move_hole',
|
||||
user_id=v.id,
|
||||
target_post_id=post.id,
|
||||
_note=f'{hole_from_str} → {hole_to_str}',
|
||||
)
|
||||
g.db.add(ma)
|
||||
position = f'a /h/{hole_from} mod'
|
||||
|
||||
if hole_from == None:
|
||||
hole_from_in_notif = 'the main feed'
|
||||
else:
|
||||
hole_from_in_notif = f'/h/{hole_from}'
|
||||
|
||||
message = f"@{v.username} ({position}) has moved [{post.title}]({post.shortlink}) from {hole_from_in_notif} to {hole_to_in_notif}"
|
||||
send_repeatable_notification(post.author_id, message)
|
||||
|
||||
cache.delete_memoized(frontlist)
|
||||
|
||||
return f"Post moved to {hole_to_in_notif} successfully!"
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<div class="modal fade" id="changeHoleModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Change Hole</h5>
|
||||
<button type="button" class="close" data-bs-dismiss="modal">
|
||||
<span><i class="fas fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class='mt-2' for="title">Hole</label>
|
||||
<div class="input-group">
|
||||
{%- set hole_placeholder = 'Required' if HOLE_REQUIRED else 'Optional' -%}
|
||||
<input list="holes" autocomplete="off" id="hole_to" class="form-control" placeholder="{{hole_placeholder}}" {% if HOLE_REQUIRED %}required{% endif %}>
|
||||
<datalist id="holes">
|
||||
{% for h in HOLES() %}
|
||||
<option value="{{h}}"></option>
|
||||
{% endfor %}
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-link text-muted" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" id="changeHoleButton" class="btn btn-primary btn-danger" data-bs-dismiss="modal">Change Hole</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script defer src="{{'js/change_hole_modal.js' | asset}}"></script>
|
|
@ -339,8 +339,15 @@
|
|||
</div>
|
||||
|
||||
{% if v %}
|
||||
{% if v.id == p.author_id %}{% include "modals/delete_post.html" %}{% endif %}
|
||||
{% if v.id == p.author_id %}
|
||||
{% include "modals/delete_post.html" %}
|
||||
{% endif %}
|
||||
{% include "modals/report_post.html" %}
|
||||
|
||||
{% if p.hole_changable(v) %}
|
||||
{% include "modals/change_hole.html" %}
|
||||
{% endif %}
|
||||
|
||||
{% if v.can_edit(p) %}
|
||||
<script defer src="{{'js/edit_post.js' | asset}}"></script>
|
||||
{% endif %}
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
<button type="button" id="unsave-{{p.id}}" class="{% if not p.id in v.saved_idlist %}d-none{% endif %} list-inline-item" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unsave_post/{{p.id}}','save-{{p.id}}','unsave-{{p.id}}','d-none')"><i class="fas fa-save"></i>Unsave {% if p.num_savers %}<span data-bs-toggle="tooltip" data-bs-placement="bottom" title="Number of users who saved this post">[{{p.num_savers}}]</span>{% endif %}</button>
|
||||
|
||||
<button type="button" class="list-inline-item" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#reportPostModal" data-nonce="{{g.nonce}}" data-onclick="report_postModal('{{p.id}}')"><i class="fas fa-flag"></i>Report</button>
|
||||
|
||||
{% if p.hole_changable(v) %}
|
||||
<button type="button" class="list-inline-item" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#changeHoleModal" data-nonce="{{g.nonce}}" data-onclick="change_holeModal('{{p.id}}')"><i class="fas fa-manhole"></i>Change Hole</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if v and v.id == p.author_id %}
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
|
||||
<button type="button" class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#reportPostModal" data-nonce="{{g.nonce}}" data-onclick="report_postModal('{{p.id}}')"><i class="fas fa-flag text-center text-muted mr-2"></i>Report</button>
|
||||
|
||||
{% if p.hole_changable(v) %}
|
||||
<button type="button" class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#changeHoleModal" data-nonce="{{g.nonce}}" data-onclick="change_holeModal('{{p.id}}')"><i class="fas fa-manhole text-center text-muted mr-2"></i>Change Hole</button>
|
||||
{% endif %}
|
||||
|
||||
{% if FEATURES['AWARDS'] -%}
|
||||
<button type="button" class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#awardModal" data-url='/award/post/{{p.id}}' data-immune="{{p.author.immune_to_negative_awards(v)}}" data-ghost="{{p.ghost}}" data-nonce="{{g.nonce}}"><i class="fas fa-gift text-center text-muted mr-2"></i>Give Award</button>
|
||||
{%- endif %}
|
||||
|
|
|
@ -250,6 +250,7 @@
|
|||
{% if v %}
|
||||
{% include "modals/delete_post.html" %}
|
||||
{% include "modals/report_post.html" %}
|
||||
{% include "modals/change_hole.html" %}
|
||||
{% if v.admin_level >= PERMS['USER_BAN'] %}
|
||||
{% include "modals/punish.html" %}
|
||||
{% endif %}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
{%- set hole_placeholder = 'Required' if HOLE_REQUIRED else 'Optional' -%}
|
||||
<input list="holes" autocomplete="off" id="hole" class="form-control" form="submitform" name="hole" data-nonce="{{g.nonce}}" data-oninput="savetext()" {% if hole %}value="{{hole}}"{% endif %} placeholder="{{hole_placeholder}}" {% if HOLE_REQUIRED %}required{% endif %}>
|
||||
<datalist id="holes">
|
||||
{% for h in HOLES %}
|
||||
{% for h in HOLES() %}
|
||||
<option value="{{h}}"></option>
|
||||
{% endfor %}
|
||||
</datalist>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
update modactions set kind='change_hole' where kind='move_hole';
|
||||
update hole_actions set kind='change_hole' where kind='move_hole';
|
Loading…
Reference in New Issue