def manage_thumbnail_get_(request): form = request.web_input(submitid="", charid="", auto="") submitid = define.get_int(form.submitid) charid = define.get_int(form.charid) if submitid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid(submitid=submitid): return Response(define.errorpage(request.userid, errorcode.permissions)) elif charid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid(charid=charid): return Response(define.errorpage(request.userid, errorcode.permissions)) elif not submitid and not charid: return Response(define.errorpage(request.userid)) if charid: source_path = define.url_make(charid, "char/.thumb", root=True) if os.path.exists(source_path): source = define.url_make(charid, "char/.thumb") else: source = define.url_make(charid, "char/cover") else: try: source = thumbnail.thumbnail_source(submitid)['display_url'] except WeasylError: source = None return Response(define.webpage(request.userid, "manage/thumbnail.html", [ # Feature "submit" if submitid else "char", # Targetid define.get_targetid(submitid, charid), # Thumbnail source, # Exists bool(source), ], options=['imageselect'], title="Select Thumbnail"))
def GET(self): form = web.input(submitid="") form.submitid = define.get_int(form.submitid) if self.user_id != define.get_ownerid(submitid=form.submitid): return define.errorpage(self.user_id, errorcode.permission) return define.webpage(self.user_id, "submit/reupload_cover.html", [form.submitid])
def reupload_cover_get_(request): form = request.web_input(submitid="") form.submitid = define.get_int(form.submitid) if request.userid != define.get_ownerid(submitid=form.submitid): raise WeasylError('InsufficientPermissions') return Response(define.webpage(request.userid, "submit/reupload_cover.html", [form.submitid], title="Reupload Cover Artwork"))
def reupload_cover_get_(request): form = request.web_input(submitid="") form.submitid = define.get_int(form.submitid) if request.userid != define.get_ownerid(submitid=form.submitid): return Response(define.errorpage(request.userid, errorcode.permission)) return Response(define.webpage(request.userid, "submit/reupload_cover.html", [form.submitid]))
def reupload_character_post_(request): form = request.web_input(targetid="", submitfile="") form.targetid = define.get_int(form.targetid) if request.userid != define.get_ownerid(charid=form.targetid): return Response(define.errorpage(request.userid, errorcode.permission)) character.reupload(request.userid, form.targetid, form.submitfile) raise HTTPSeeOther(location="/character/%i" % (form.targetid,))
def reupload_character_post_(request): form = request.web_input(targetid="", submitfile="") form.targetid = define.get_int(form.targetid) if request.userid != define.get_ownerid(charid=form.targetid): return Response(define.errorpage(request.userid, errorcode.permission)) character.reupload(request.userid, form.targetid, form.submitfile) raise HTTPSeeOther(location="/character/%i" % (form.targetid, ))
def POST(self): form = web.input(targetid="", submitfile="") form.targetid = define.get_int(form.targetid) if self.user_id != define.get_ownerid(charid=form.targetid): return define.errorpage(self.user_id, errorcode.permission) character.reupload(self.user_id, form.targetid, form.submitfile) raise web.seeother("/character/%i" % (form.targetid,))
def reupload_character_post_(request): form = request.web_input(targetid="", submitfile="") form.targetid = define.get_int(form.targetid) if request.userid != define.get_ownerid(charid=form.targetid): raise WeasylError('InsufficientPermissions') character.reupload(request.userid, form.targetid, form.submitfile) raise HTTPSeeOther(location="/character/%i" % (form.targetid, ))
def POST(self): form = web.input(targetid="", submitfile="") form.targetid = define.get_int(form.targetid) if self.user_id != define.get_ownerid(charid=form.targetid): return define.errorpage(self.user_id, errorcode.permission) character.reupload(self.user_id, form.targetid, form.submitfile) raise web.seeother("/character/%i" % (form.targetid, ))
def manage_thumbnail_get_(request): form = request.web_input(submitid="", charid="", auto="") submitid = define.get_int(form.submitid) charid = define.get_int(form.charid) if submitid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid( submitid=submitid): return Response(define.errorpage(request.userid, errorcode.permissions)) elif charid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid( charid=charid): return Response(define.errorpage(request.userid, errorcode.permissions)) elif not submitid and not charid: return Response(define.errorpage(request.userid)) if charid: source_path = define.url_make(charid, "char/.thumb", root=True) if os.path.exists(source_path): source = define.url_make(charid, "char/.thumb") else: source = define.url_make(charid, "char/cover") else: try: source = thumbnail.thumbnail_source(submitid)['display_url'] except WeasylError: source = None return Response( define.webpage( request.userid, "manage/thumbnail.html", [ # Feature "submit" if submitid else "char", # Targetid define.get_targetid(submitid, charid), # Thumbnail source, # Exists bool(source), ], options=['imageselect'], title="Select Thumbnail"))
def manage_thumbnail_post_(request): form = request.web_input(submitid="", charid="", x1="", y1="", x2="", y2="", thumbfile="") submitid = define.get_int(form.submitid) charid = define.get_int(form.charid) if submitid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid( submitid=submitid): return Response(define.errorpage(request.userid)) if charid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid( charid=charid): return Response(define.errorpage(request.userid)) if not submitid and not charid: return Response(define.errorpage(request.userid)) if form.thumbfile: thumbnail.upload(request.userid, form.thumbfile, submitid=submitid, charid=charid) if submitid: raise HTTPSeeOther(location="/manage/thumbnail?submitid=%i" % (submitid, )) else: raise HTTPSeeOther(location="/manage/thumbnail?charid=%i" % (charid, )) else: thumbnail.create(request.userid, form.x1, form.y1, form.x2, form.y2, submitid=submitid, charid=charid) if submitid: raise HTTPSeeOther(location="/submission/%i" % (submitid, )) else: raise HTTPSeeOther(location="/character/%i" % (charid, ))
def reupload_cover_get_(request): form = request.web_input(submitid="") form.submitid = define.get_int(form.submitid) if request.userid != define.get_ownerid(submitid=form.submitid): return Response(define.errorpage(request.userid, errorcode.permission)) return Response( define.webpage(request.userid, "submit/reupload_cover.html", [form.submitid]))
def POST(self): form = web.input(submitid="", charid="", x1="", y1="", x2="", y2="", thumbfile="") submitid = define.get_int(form.submitid) charid = define.get_int(form.charid) if submitid and self.user_id not in staff.ADMINS and self.user_id != define.get_ownerid( submitid=submitid): return define.errorpage(self.user_id) if charid and self.user_id not in staff.ADMINS and self.user_id != define.get_ownerid( charid=charid): return define.errorpage(self.user_id) if not submitid and not charid: return define.errorpage(self.user_id) if form.thumbfile: thumbnail.upload(self.user_id, form.thumbfile, submitid=submitid, charid=charid) if submitid: raise web.seeother("/manage/thumbnail?submitid=%i" % (submitid, )) else: raise web.seeother("/manage/thumbnail?charid=%i" % (charid, )) else: thumbnail.create(self.user_id, form.x1, form.y1, form.x2, form.y2, submitid=submitid, charid=charid) if submitid: raise web.seeother("/submission/%i" % (submitid, )) else: raise web.seeother("/character/%i" % (charid, ))
def reupload_character_get_(request): form = request.web_input(charid="") form.charid = define.get_int(form.charid) if request.userid != define.get_ownerid(charid=form.charid): raise WeasylError('InsufficientPermissions') return Response(define.webpage(request.userid, "submit/reupload_submission.html", [ "character", # charid form.charid, ], title="Reupload Character Image"))
def reupload_submission_get_(request): form = request.web_input(submitid="") form.submitid = define.get_int(form.submitid) if request.userid != define.get_ownerid(submitid=form.submitid): return Response(define.errorpage(request.userid, errorcode.permission)) return Response(define.webpage(request.userid, "submit/reupload_submission.html", [ "submission", # SubmitID form.submitid, ], title="Reupload Submission"))
def GET(self): form = web.input(charid="") form.charid = define.get_int(form.charid) if self.user_id != define.get_ownerid(charid=form.charid): return define.errorpage(self.user_id, errorcode.permission) return define.webpage(self.user_id, "submit/reupload_submission.html", [ "character", # charid form.charid, ])
def reupload_submission_get_(request): form = request.web_input(submitid="") form.submitid = define.get_int(form.submitid) if request.userid != define.get_ownerid(submitid=form.submitid): raise WeasylError('InsufficientPermissions') return Response(define.webpage(request.userid, "submit/reupload_submission.html", [ "submission", # SubmitID form.submitid, ], title="Reupload Submission"))
def reupload_character_get_(request): form = request.web_input(charid="") form.charid = define.get_int(form.charid) if request.userid != define.get_ownerid(charid=form.charid): return Response(define.errorpage(request.userid, errorcode.permission)) return Response(define.webpage(request.userid, "submit/reupload_submission.html", [ "character", # charid form.charid, ]))
def remove(userid, journalid): ownerid = d.get_ownerid(journalid=journalid) if userid not in staff.MODS and userid != ownerid: raise WeasylError("InsufficientPermissions") query = d.execute("UPDATE journal SET settings = settings || 'h'" " WHERE journalid = %i AND settings !~ 'h' RETURNING journalid", [journalid]) if query: welcome.journal_remove(journalid) return ownerid
def remove(userid, submitid): ownerid = d.get_ownerid(submitid=submitid) if userid not in staff.MODS and userid != ownerid: raise WeasylError("InsufficientPermissions") query = d.execute("UPDATE submission SET settings = settings || 'h'" " WHERE submitid = %i AND settings !~ 'h' RETURNING submitid", [submitid]) if query: welcome.submission_remove(submitid) return ownerid
def remove(userid, charid): ownerid = define.get_ownerid(charid=charid) if userid not in staff.MODS and userid != ownerid: raise WeasylError("InsufficientPermissions") query = define.execute("UPDATE character SET settings = settings || 'h'" " WHERE charid = %i AND settings !~ 'h'" " RETURNING charid", [charid]) if query: welcome.character_remove(charid) return ownerid
def POST(self): form = web.input(submitid="", charid="", x1="", y1="", x2="", y2="", thumbfile="") submitid = define.get_int(form.submitid) charid = define.get_int(form.charid) if submitid and self.user_id not in staff.ADMINS and self.user_id != define.get_ownerid(submitid=submitid): return define.errorpage(self.user_id) if charid and self.user_id not in staff.ADMINS and self.user_id != define.get_ownerid(charid=charid): return define.errorpage(self.user_id) if not submitid and not charid: return define.errorpage(self.user_id) if form.thumbfile: thumbnail.upload(self.user_id, form.thumbfile, submitid=submitid, charid=charid) if submitid: raise web.seeother("/manage/thumbnail?submitid=%i" % (submitid,)) else: raise web.seeother("/manage/thumbnail?charid=%i" % (charid,)) else: thumbnail.create(self.user_id, form.x1, form.y1, form.x2, form.y2, submitid=submitid, charid=charid) if submitid: raise web.seeother("/submission/%i" % (submitid,)) else: raise web.seeother("/character/%i" % (charid,))
def manage_thumbnail_post_(request): form = request.web_input(submitid="", charid="", x1="", y1="", x2="", y2="", thumbfile="") submitid = define.get_int(form.submitid) charid = define.get_int(form.charid) if submitid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid(submitid=submitid): return Response(define.errorpage(request.userid)) if charid and request.userid not in staff.ADMINS and request.userid != define.get_ownerid(charid=charid): return Response(define.errorpage(request.userid)) if not submitid and not charid: return Response(define.errorpage(request.userid)) if form.thumbfile: thumbnail.upload(request.userid, form.thumbfile, submitid=submitid, charid=charid) if submitid: raise HTTPSeeOther(location="/manage/thumbnail?submitid=%i" % (submitid,)) else: raise HTTPSeeOther(location="/manage/thumbnail?charid=%i" % (charid,)) else: thumbnail.create(request.userid, form.x1, form.y1, form.x2, form.y2, submitid=submitid, charid=charid) if submitid: raise HTTPSeeOther(location="/submission/%i" % (submitid,)) else: raise HTTPSeeOther(location="/character/%i" % (charid,))
def GET(self): form = web.input(charid="") form.charid = define.get_int(form.charid) if self.user_id != define.get_ownerid(charid=form.charid): return define.errorpage(self.user_id, errorcode.permission) return define.webpage( self.user_id, "submit/reupload_submission.html", [ "character", # charid form.charid, ])
def reupload_character_get_(request): form = request.web_input(charid="") form.charid = define.get_int(form.charid) if request.userid != define.get_ownerid(charid=form.charid): return Response(define.errorpage(request.userid, errorcode.permission)) return Response( define.webpage( request.userid, "submit/reupload_submission.html", [ "character", # charid form.charid, ]))
def collection_request_(request): form = request.web_input(submitid="") form.submitid = int(form.submitid) form.otherid = define.get_ownerid(submitid=form.submitid) if not form.otherid: raise WeasylError("userRecordMissing") if request.userid == form.otherid: raise WeasylError("cannotSelfCollect") collection.request(request.userid, form.submitid, form.otherid) return Response(define.errorpage( request.userid, "**Success!** Your collection request has been sent. " "The submission author may approve or reject this request.", [["Go Back", "/submission/%i" % (form.submitid,)], ["Return to the Home Page", "/index"]]))
def reupload_submission_get_(request): form = request.web_input(submitid="") form.submitid = define.get_int(form.submitid) if request.userid != define.get_ownerid(submitid=form.submitid): return Response(define.errorpage(request.userid, errorcode.permission)) return Response( define.webpage( request.userid, "submit/reupload_submission.html", [ "submission", # SubmitID form.submitid, ], title="Reupload Submission"))
def associate(userid, tags, submitid=None, charid=None, journalid=None): targetid = d.get_targetid(submitid, charid, journalid) # Assign table, feature, ownerid if submitid: table, feature = "searchmapsubmit", "submit" ownerid = d.get_ownerid(submitid=targetid) elif charid: table, feature = "searchmapchar", "char" ownerid = d.get_ownerid(charid=targetid) else: table, feature = "searchmapjournal", "journal" ownerid = d.get_ownerid(journalid=targetid) # Check permissions and invalid target if not ownerid: raise WeasylError("TargetRecordMissing") elif userid != ownerid and "g" in d.get_config(userid): raise WeasylError("InsufficientPermissions") elif ignoreuser.check(ownerid, userid): raise WeasylError("contentOwnerIgnoredYou") # Determine previous tags existing = d.engine.execute( "SELECT tagid, settings FROM {} WHERE targetid = %(target)s".format(table), target=targetid).fetchall() # Determine tag titles and tagids query = d.engine.execute( "SELECT tagid, title FROM searchtag WHERE title = ANY (%(tags)s)", tags=list(tags)).fetchall() newtags = list(tags - {x.title for x in query}) if newtags: query.extend( d.engine.execute( "INSERT INTO searchtag (title) SELECT * FROM UNNEST (%(newtags)s) AS title RETURNING tagid, title", newtags=newtags ).fetchall()) existing_tagids = {t.tagid for t in existing} entered_tagids = {t.tagid for t in query} # Assign added and removed added = entered_tagids - existing_tagids removed = existing_tagids - entered_tagids # Check removed artist tags if not can_remove_tags(userid, ownerid): existing_artist_tags = {t.tagid for t in existing if 'a' in t.settings} removed.difference_update(existing_artist_tags) entered_tagids.update(existing_artist_tags) # Remove tags if removed: d.engine.execute( "DELETE FROM {} WHERE targetid = %(target)s AND tagid = ANY (%(removed)s)".format(table), target=targetid, removed=list(removed)) if added: d.execute("INSERT INTO %s VALUES %s" % (table, d.sql_number_series([[i, targetid] for i in added]))) if userid == ownerid: d.execute( "UPDATE %s SET settings = settings || 'a' WHERE targetid = %i AND tagid IN %s", [table, targetid, d.sql_number_list(list(added))]) if submitid: try: d.engine.execute( 'INSERT INTO submission_tags (submitid, tags) VALUES (%(submission)s, %(tags)s)', submission=submitid, tags=list(entered_tagids)) except PostgresError: result = d.engine.execute( 'UPDATE submission_tags SET tags = %(tags)s WHERE submitid = %(submission)s', submission=submitid, tags=list(entered_tagids)) assert result.rowcount == 1 db = d.connect() db.execute( d.meta.tables['tag_updates'].insert() .values(submitid=submitid, userid=userid, added=tag_array(added), removed=tag_array(removed))) if userid != ownerid: welcome.tag_update_insert(ownerid, submitid) files.append( "%stag.%s.%s.log" % (m.MACRO_SYS_LOG_PATH, feature, d.get_timestamp()), "-%sID %i -T %i -UID %i -X %s\n" % (feature[0].upper(), targetid, d.get_time(), userid, " ".join(tags)))
def associate(userid, tags, submitid=None, charid=None, journalid=None, preferred_tags_userid=None, optout_tags_userid=None): """ Associates searchtags with a content item. Parameters: userid: The userid of the user associating tags tags: A set of tags submitid: The ID number of a submission content item to associate ``tags`` to. (default: None) charid: The ID number of a character content item to associate ``tags`` to. (default: None) journalid: The ID number of a journal content item to associate ``tags`` to. (default: None) preferred_tags_userid: The ID number of a user to associate ``tags`` to for Preferred tags. (default: None) optout_tags_userid: The ID number of a user to associate ``tags`` to for Opt-Out tags. (default: None) Returns: A dict containing two elements. 1) ``add_failure_restricted_tags``, which contains a space separated string of tag titles which failed to be added to the content item due to the user or global restricted tag lists; and 2) ``remove_failure_owner_set_tags``, which contains a space separated string of tag titles which failed to be removed from the content item due to the owner of the aforementioned item prohibiting users from removing tags set by the content owner. If an element does not have tags, the element is set to None. If neither elements are set, the function returns None. """ targetid = d.get_targetid(submitid, charid, journalid) # Assign table, feature, ownerid if submitid: table, feature = "searchmapsubmit", "submit" ownerid = d.get_ownerid(submitid=targetid) elif charid: table, feature = "searchmapchar", "char" ownerid = d.get_ownerid(charid=targetid) elif journalid: table, feature = "searchmapjournal", "journal" ownerid = d.get_ownerid(journalid=targetid) elif preferred_tags_userid: table, feature = "artist_preferred_tags", "user" targetid = ownerid = preferred_tags_userid elif optout_tags_userid: table, feature = "artist_optout_tags", "user" targetid = ownerid = optout_tags_userid else: raise WeasylError("Unexpected") # Check permissions and invalid target if not ownerid: raise WeasylError("TargetRecordMissing") elif userid != ownerid and ("g" in d.get_config(userid) or preferred_tags_userid or optout_tags_userid): # disallow if user is forbidden from tagging, or trying to set artist tags on someone other than themselves raise WeasylError("InsufficientPermissions") elif ignoreuser.check(ownerid, userid): raise WeasylError("contentOwnerIgnoredYou") # Determine previous tagids, titles, and settings existing = d.engine.execute( "SELECT tagid, title, settings FROM {} INNER JOIN searchtag USING (tagid) WHERE targetid = %(target)s" .format(table), target=targetid).fetchall() # Retrieve tag titles and tagid pairs, for new (if any) and existing tags query = add_and_get_searchtags(tags) existing_tagids = {t.tagid for t in existing} entered_tagids = {t.tagid for t in query} # Assign added and removed added = entered_tagids - existing_tagids removed = existing_tagids - entered_tagids # enforce the limit on artist preference tags if preferred_tags_userid and (len(added) - len(removed) + len(existing)) > MAX_PREFERRED_TAGS: raise WeasylError("tooManyPreferenceTags") # Track which tags fail to be added or removed to later notify the user (Note: These are tagids at this stage) add_failure_restricted_tags = None remove_failure_owner_set_tags = None # If the modifying user is not the owner of the object, and is not staff, check user/global restriction lists if userid != ownerid and userid not in staff.MODS: user_rtags = set(query_user_restricted_tags(ownerid)) global_rtags = set(query_global_restricted_tags()) add_failure_restricted_tags = remove_restricted_tags( user_rtags | global_rtags, query) added -= add_failure_restricted_tags if len(add_failure_restricted_tags) == 0: add_failure_restricted_tags = None # Check removed artist tags if not can_remove_tags(userid, ownerid): existing_artist_tags = {t.tagid for t in existing if 'a' in t.settings} remove_failure_owner_set_tags = removed & existing_artist_tags removed.difference_update(existing_artist_tags) entered_tagids.update(existing_artist_tags) # Submission items use a different method of tag protection for artist tags; ignore them if submitid or len(remove_failure_owner_set_tags) == 0: remove_failure_owner_set_tags = None # Remove tags if removed: d.engine.execute( "DELETE FROM {} WHERE targetid = %(target)s AND tagid = ANY (%(removed)s)" .format(table), target=targetid, removed=list(removed)) if added: d.engine.execute( "INSERT INTO {} SELECT tag, %(target)s FROM UNNEST (%(added)s) AS tag" .format(table), target=targetid, added=list(added)) # preference/optout tags can only be set by the artist, so this settings column does not apply if userid == ownerid and not (preferred_tags_userid or optout_tags_userid): d.engine.execute( "UPDATE {} SET settings = settings || 'a' WHERE targetid = %(target)s AND tagid = ANY (%(added)s)" .format(table), target=targetid, added=list(added)) if submitid: d.engine.execute( 'INSERT INTO submission_tags (submitid, tags) VALUES (%(submission)s, %(tags)s) ' 'ON CONFLICT (submitid) DO UPDATE SET tags = %(tags)s', submission=submitid, tags=list(entered_tagids)) db = d.connect() db.execute(d.meta.tables['tag_updates'].insert().values( submitid=submitid, userid=userid, added=tag_array(added), removed=tag_array(removed))) if userid != ownerid: welcome.tag_update_insert(ownerid, submitid) files.append( "%stag.%s.%s.log" % (m.MACRO_SYS_LOG_PATH, feature, d.get_timestamp()), "-%sID %i -T %i -UID %i -X %s\n" % (feature[0].upper(), targetid, d.get_time(), userid, " ".join(tags))) # Return dict with any tag titles as a string that failed to be added or removed if add_failure_restricted_tags or remove_failure_owner_set_tags: if add_failure_restricted_tags: add_failure_restricted_tags = " ".join({ tag.title for tag in query if tag.tagid in add_failure_restricted_tags }) if remove_failure_owner_set_tags: remove_failure_owner_set_tags = " ".join({ tag.title for tag in existing if tag.tagid in remove_failure_owner_set_tags }) return { "add_failure_restricted_tags": add_failure_restricted_tags, "remove_failure_owner_set_tags": remove_failure_owner_set_tags } else: return None
def associate(userid, tags, submitid=None, charid=None, journalid=None, preferred_tags_userid=None, optout_tags_userid=None): """ Associates searchtags with a content item. Parameters: userid: The userid of the user associating tags tags: A set of tags submitid: The ID number of a submission content item to associate ``tags`` to. (default: None) charid: The ID number of a character content item to associate ``tags`` to. (default: None) journalid: The ID number of a journal content item to associate ``tags`` to. (default: None) preferred_tags_userid: The ID number of a user to associate ``tags`` to for Preferred tags. (default: None) optout_tags_userid: The ID number of a user to associate ``tags`` to for Opt-Out tags. (default: None) Returns: A dict containing two elements. 1) ``add_failure_restricted_tags``, which contains a space separated string of tag titles which failed to be added to the content item due to the user or global restricted tag lists; and 2) ``remove_failure_owner_set_tags``, which contains a space separated string of tag titles which failed to be removed from the content item due to the owner of the aforementioned item prohibiting users from removing tags set by the content owner. If an element does not have tags, the element is set to None. If neither elements are set, the function returns None. """ targetid = d.get_targetid(submitid, charid, journalid) # Assign table, feature, ownerid if submitid: table, feature = "searchmapsubmit", "submit" ownerid = d.get_ownerid(submitid=targetid) elif charid: table, feature = "searchmapchar", "char" ownerid = d.get_ownerid(charid=targetid) elif journalid: table, feature = "searchmapjournal", "journal" ownerid = d.get_ownerid(journalid=targetid) elif preferred_tags_userid: table, feature = "artist_preferred_tags", "user" targetid = ownerid = preferred_tags_userid elif optout_tags_userid: table, feature = "artist_optout_tags", "user" targetid = ownerid = optout_tags_userid else: raise WeasylError("Unexpected") # Check permissions and invalid target if not ownerid: raise WeasylError("TargetRecordMissing") elif userid != ownerid and ("g" in d.get_config(userid) or preferred_tags_userid or optout_tags_userid): # disallow if user is forbidden from tagging, or trying to set artist tags on someone other than themselves raise WeasylError("InsufficientPermissions") elif ignoreuser.check(ownerid, userid): raise WeasylError("contentOwnerIgnoredYou") # Determine previous tagids, titles, and settings existing = d.engine.execute( "SELECT tagid, title, settings FROM {} INNER JOIN searchtag USING (tagid) WHERE targetid = %(target)s".format(table), target=targetid).fetchall() # Retrieve tag titles and tagid pairs, for new (if any) and existing tags query = add_and_get_searchtags(tags) existing_tagids = {t.tagid for t in existing} entered_tagids = {t.tagid for t in query} # Assign added and removed added = entered_tagids - existing_tagids removed = existing_tagids - entered_tagids # enforce the limit on artist preference tags if preferred_tags_userid and (len(added) - len(removed) + len(existing)) > MAX_PREFERRED_TAGS: raise WeasylError("tooManyPreferenceTags") # Track which tags fail to be added or removed to later notify the user (Note: These are tagids at this stage) add_failure_restricted_tags = None remove_failure_owner_set_tags = None # If the modifying user is not the owner of the object, and is not staff, check user/global restriction lists if userid != ownerid and userid not in staff.MODS: user_rtags = set(query_user_restricted_tags(ownerid)) global_rtags = set(query_global_restricted_tags()) add_failure_restricted_tags = remove_restricted_tags(user_rtags | global_rtags, query) added -= add_failure_restricted_tags if len(add_failure_restricted_tags) == 0: add_failure_restricted_tags = None # Check removed artist tags if not can_remove_tags(userid, ownerid): existing_artist_tags = {t.tagid for t in existing if 'a' in t.settings} remove_failure_owner_set_tags = removed & existing_artist_tags removed.difference_update(existing_artist_tags) entered_tagids.update(existing_artist_tags) # Submission items use a different method of tag protection for artist tags; ignore them if submitid or len(remove_failure_owner_set_tags) == 0: remove_failure_owner_set_tags = None # Remove tags if removed: d.engine.execute( "DELETE FROM {} WHERE targetid = %(target)s AND tagid = ANY (%(removed)s)".format(table), target=targetid, removed=list(removed)) if added: d.engine.execute( "INSERT INTO {} SELECT tag, %(target)s FROM UNNEST (%(added)s) AS tag".format(table), target=targetid, added=list(added)) # preference/optout tags can only be set by the artist, so this settings column does not apply if userid == ownerid and not (preferred_tags_userid or optout_tags_userid): d.execute( "UPDATE %s SET settings = settings || 'a' WHERE targetid = %i AND tagid IN %s", [table, targetid, d.sql_number_list(list(added))]) if submitid: d.engine.execute( 'INSERT INTO submission_tags (submitid, tags) VALUES (%(submission)s, %(tags)s) ' 'ON CONFLICT (submitid) DO UPDATE SET tags = %(tags)s', submission=submitid, tags=list(entered_tagids)) db = d.connect() db.execute( d.meta.tables['tag_updates'].insert() .values(submitid=submitid, userid=userid, added=tag_array(added), removed=tag_array(removed))) if userid != ownerid: welcome.tag_update_insert(ownerid, submitid) files.append( "%stag.%s.%s.log" % (m.MACRO_SYS_LOG_PATH, feature, d.get_timestamp()), "-%sID %i -T %i -UID %i -X %s\n" % (feature[0].upper(), targetid, d.get_time(), userid, " ".join(tags))) # Return dict with any tag titles as a string that failed to be added or removed if add_failure_restricted_tags or remove_failure_owner_set_tags: if add_failure_restricted_tags: add_failure_restricted_tags = " ".join({tag.title for tag in query if tag.tagid in add_failure_restricted_tags}) if remove_failure_owner_set_tags: remove_failure_owner_set_tags = " ".join({tag.title for tag in existing if tag.tagid in remove_failure_owner_set_tags}) return {"add_failure_restricted_tags": add_failure_restricted_tags, "remove_failure_owner_set_tags": remove_failure_owner_set_tags} else: return None
def associate(userid, tags, submitid=None, charid=None, journalid=None): targetid = d.get_targetid(submitid, charid, journalid) # Assign table, feature, ownerid if submitid: table, feature = "searchmapsubmit", "submit" ownerid = d.get_ownerid(submitid=targetid) elif charid: table, feature = "searchmapchar", "char" ownerid = d.get_ownerid(charid=targetid) else: table, feature = "searchmapjournal", "journal" ownerid = d.get_ownerid(journalid=targetid) # Check permissions and invalid target if not ownerid: raise WeasylError("TargetRecordMissing") elif userid != ownerid and "g" in d.get_config(userid): raise WeasylError("InsufficientPermissions") elif ignoreuser.check(ownerid, userid): raise WeasylError("contentOwnerIgnoredYou") # Determine previous tags existing = d.engine.execute( "SELECT tagid, settings FROM {} WHERE targetid = %(target)s".format(table), target=targetid).fetchall() # Determine tag titles and tagids query = d.engine.execute( "SELECT tagid, title FROM searchtag WHERE title = ANY (%(tags)s)", tags=list(tags)).fetchall() newtags = list(tags - {x.title for x in query}) if newtags: query.extend( d.engine.execute( "INSERT INTO searchtag (title) SELECT * FROM UNNEST (%(newtags)s) AS title RETURNING tagid, title", newtags=newtags ).fetchall()) existing_tagids = {t.tagid for t in existing} entered_tagids = {t.tagid for t in query} # Assign added and removed added = entered_tagids - existing_tagids removed = existing_tagids - entered_tagids # Check removed artist tags if not can_remove_tags(userid, ownerid): existing_artist_tags = {t.tagid for t in existing if 'a' in t.settings} removed.difference_update(existing_artist_tags) entered_tagids.update(existing_artist_tags) # Remove tags if removed: d.engine.execute( "DELETE FROM {} WHERE targetid = %(target)s AND tagid = ANY (%(removed)s)".format(table), target=targetid, removed=list(removed)) if added: d.engine.execute( "INSERT INTO {} SELECT tag, %(target)s FROM UNNEST (%(added)s) AS tag".format(table), target=targetid, added=list(added)) if userid == ownerid: d.execute( "UPDATE %s SET settings = settings || 'a' WHERE targetid = %i AND tagid IN %s", [table, targetid, d.sql_number_list(list(added))]) if submitid: d.engine.execute( 'INSERT INTO submission_tags (submitid, tags) VALUES (%(submission)s, %(tags)s) ' 'ON CONFLICT (submitid) DO UPDATE SET tags = %(tags)s', submission=submitid, tags=list(entered_tagids)) db = d.connect() db.execute( d.meta.tables['tag_updates'].insert() .values(submitid=submitid, userid=userid, added=tag_array(added), removed=tag_array(removed))) if userid != ownerid: welcome.tag_update_insert(ownerid, submitid) files.append( "%stag.%s.%s.log" % (m.MACRO_SYS_LOG_PATH, feature, d.get_timestamp()), "-%sID %i -T %i -UID %i -X %s\n" % (feature[0].upper(), targetid, d.get_time(), userid, " ".join(tags)))