def vote(request, url_param): # Fetch the article from the URL parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] # Fetch all proposals for a given article that have not been verified unverifiedProposals = EditProposal.objects.filter( article_id=articleObject.id, chainverified=False) # Loop through the unverified proposals for proposal in unverifiedProposals: try: print("Processing proposal %s" % proposal.id) cacheFinalizedResult(proposal.id, True) except: pass # Fetch all proposals for a given article allProposals = EditProposal.objects.filter( article_id=articleObject.id).order_by('-endtime') # Return the page HTML return render(request, 'enterlink/votehistory.html', { "articleObject": articleObject, "allProposals": allProposals })
def hoverBlurb(request, url_param, isAJAX=False): # Get the article object from the URL parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] # Handle removed pages try: if articleObject.is_removed == True: return HttpResponseRedirect('/error/') except: pass # Get all the data from the article and pass it to the Django template contextDictionary = {} contextDictionary.update({"ARTICLE_NAME": articleObject.page_title}) contextDictionary.update({"ARTICLE_SLUG": articleObject.slug}) contextDictionary.update({"ARTICLE_SLUG_ALT": articleObject.slug_alt}) contextDictionary.update({"ARTICLE_IS_REMOVED": articleObject.is_removed}) contextDictionary.update({"ARTICLE_PHOTO_URL": articleObject.photo_url}) contextDictionary.update({"ARTICLE_THUMB_URL": articleObject.photo_thumb_url}) contextDictionary.update({"BLURB_SNIPPET": articleObject.blurb_snippet}) # Return the hoverblurb HTML if isAJAX: return render(request, "enterlink/hoverblurb_ajax_blockchain.html", contextDictionary) else: return render(request, "enterlink/hoverblurb_blockchain.html", contextDictionary)
def edit_301(url_param="create_page"): # Fetch the article object from the url parameter cleanedParamList = getTheArticleObject(url_param) cleaned_url_param = cleanedParamList[0] # Do the redirect return HttpResponsePermanentRedirect("/wiki/%s/advanced_edit/" % cleaned_url_param)
def template_handler_301_amp(url_param): # Fetch the article object from the url parameter cleanedParamList = getTheArticleObject(url_param) cleaned_url_param = cleanedParamList[0] # Do the redirect return HttpResponsePermanentRedirect("/wiki/%s/amp/" % cleaned_url_param)
def AJAX_Picture_Upload(request, photo_type, identifier, existingActivity=None): # See if the photo is a profile picture if photo_type == "ProfilePics": pageSlug = request.POST['pageID'] # Get the article object from the provide URL slug cleanedParamList = getTheArticleObject(pageSlug) articleObject = cleanedParamList[1] # Slugify the article title theNameSlugged = DjangoText.slugify(unicode( articleObject.page_title).encode('utf-8'), allow_unicode=True) identifier = theNameSlugged # Get the caption of the picture try: fileCaption = request.POST['caption'] except: fileCaption = ugettext( "This is the reference link for the lead picture/gif of the page. Delete this link here or replace the picture/gif above." ) # Get the image file image_file = request.FILES['file'] image_file_thumb = request.FILES['file'] # Find the MIME type for the image try: theMIME = magic.from_buffer(image_file.read(), mime=True) except: theMIME = MimeTypes().guess_type(image_file.name) # Seek to the beginning of the image buffer image_file.seek(0) # Format and gzip the image photoResult = processPhoto(image_file, theMIME, photo_type, identifier, fileCaption) # Update the article object if the upload was for a profile picture if photo_type == "ProfilePics": mainPhotoURL = photoResult["mainPhotoURL"].replace( 'https://everipedia-storage.s3.amazonaws.com/', 'https://everipedia-storage.s3-accelerate.amazonaws.com/') thumbnailPhotoURL = photoResult["thumbnailPhotoURL"].replace( 'https://everipedia-storage.s3.amazonaws.com/', 'https://everipedia-storage.s3-accelerate.amazonaws.com/') articleObject.photo_url = mainPhotoURL articleObject.photo_thumb_url = thumbnailPhotoURL articleObject.save() # Return the result of this upload process return JsonResponse(photoResult["returnDict"])
def AJAX_Schema_Search(request): # Fetch the search term from the GET parameter searchterm = request.GET['searchterm'] # Get the article object from the provided slug cleanedParamList = getTheArticleObject(request.GET['article_slug']) articleObject = cleanedParamList[1] # Determine what the page type is. Example: https://schema.org/Person pageTypeToUse = "Person" if ( articleObject.page_type is None or articleObject.page_type == "") else articleObject.page_type # Fetch all the possible schema properties for the given page type schemaSet = SchemaObject.objects.filter( Q(schema_for=pageTypeToUse) | Q(schema_for='Thing'), Q(exclude_from_dropdown=0)) # Generate the list in the appropriate language localMappedList, localSchemaListOrig, localSchemaListTrans = [], [], [] for schemaNugget in schemaSet: try: localMappedList.append(ugettext(schemaNugget.mapped_keyword)) localSchemaListOrig.append(ugettext(schemaNugget.schema_keyword)) localSchemaListTrans.append(schemaNugget.schema_keyword) except: localMappedList.append(schemaNugget.mapped_keyword) localSchemaListOrig.append(schemaNugget.schema_keyword) localSchemaListTrans.append(schemaNugget.schema_keyword) # See if the search term matches (exact or partially) any of schema keywords and if they do, return them. my_list_keywords, my_list_mapped_keywords = [], [] if searchterm == "": # Return all of the possible schema properties my_list_keywords = localSchemaListOrig my_list_mapped_keywords = localMappedList else: # Look for partial or exact matches try: for index in range(0, len(localMappedList)): if (searchterm.lower() in localMappedList[index].lower()) or ( searchterm.lower() in localSchemaListTrans[index].lower()): my_list_keywords.append(localSchemaListOrig[index]) my_list_mapped_keywords.append(localMappedList[index]) except: print("Error in schema search") # JSONifying the data will make the links be displayable as data[0], data[1], etc in Javascript if schemaSet.count() == 0: schemaSet = 'nolinks' return HttpResponse("") # Format the JSON data json_data = json.dumps([my_list_keywords, my_list_mapped_keywords]) # Return the list as a JSON return HttpResponse(json_data, content_type='application/json')
def AJAX_Fetch_Page_Photo(request, url_param): # Get the article object from the url parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] # Return the photo editing HTML return render(request, 'enterlink/edit_ajax_page_photo.html', { 'articleObject': articleObject, })
def template_handler_301_amp(self, **kwargs): # For some reason, it is coming through as a kwarg url_param = kwargs["url_param"] # Fetch the article object from the url parameter cleanedParamList = getTheArticleObject(url_param) cleaned_url_param = cleanedParamList[0] # Do the redirect return HttpResponsePermanentRedirect("/wiki/%s/amp/" % cleaned_url_param)
def AJAX_Fetch_New_Infobox_Form(request, url_param): # Get the article object from the url parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] # Update the Django HTML template variables contextDictionary = {} contextDictionary.update({"ARTICLE_NAME": articleObject.page_title}) contextDictionary.update({"ARTICLE_SLUG": articleObject.slug}) contextDictionary.update({"ARTICLE_SLUG_ALT": articleObject.slug_alt}) contextDictionary.update({"ARTICLE_IS_REMOVED": articleObject.is_removed}) contextDictionary.update({"ARTICLE_PAGE_TYPE": articleObject.page_type}) # Return the HTML return render(request, 'enterlink/edit_ajax_addinfobox.html', contextDictionary)
def AJAX_Add_New_Infobox(request): # Get the POSTed variables enteredcontent = request.POST['infocontent'] infotype = request.POST['infotype'] infotype = infotype.split("~")[0] pageslug = request.POST['pageslug'] # Get the article object from the page slug cleanedParamList = getTheArticleObject(pageslug) articleObject = cleanedParamList[1] # Look to see if the provided infotype is a schema.org itemprop try: schema_info = "" # Get all the possible schema.org properties based on the page type # E.g. for "Person", it is https://schema.org/Person possibleSchemas = SchemaObject.objects.filter( schema_for=articleObject.page_type) # Encode and lowercase the infotype lowerInfotype = infotype.lower().encode('utf-8') # Check to see if the infotype submitted matches a schema.org property, accounting for language differences for schemaTest in possibleSchemas: translatedMapped = ugettext( schemaTest.mapped_keyword).lower().encode('utf-8') if (lowerInfotype == translatedMapped): schema_info = schemaTest break except SchemaObject.DoesNotExist: schema_info = '' # this means that no schema data could be found for the mapped keyword so this infobox won't be tagged by schema tags # Process the schema variable try: schematypeVariable = schema_info.schema_keyword except: schematypeVariable = "" try: addlSchematype = schema_info.schema_argument except: addlSchematype = None try: addlSchemaItemprop = schema_info.addl_schema_default_itemprop except: addlSchemaItemprop = None # Check and clean the submitted infobox content cleanedContent = badLinkSanitizer(enteredcontent) cleanedInfotype = strip_tags(badLinkSanitizer(infotype)) # Prepare variables pluralPackages = {} newIboxDict = "" # Quick split test try: quicksplit = cleanedContent.split("|") except: quicksplit = "" # Test to see if infobox is plural (multiple rows for one infotype). Example: Education: UCLA; USC; if (len(quicksplit) > 1): returnType = "PLURAL" pluralObjects = [] for pluralNugget in quicksplit: pluralObjects.append({ "key": cleanedInfotype, "value": pluralNugget, "schema": schematypeVariable, "addlSchematype": addlSchematype, "addlSchemaItemprop": addlSchemaItemprop }) pluralPackages = { "key": cleanedInfotype, "objects": pluralObjects, "schema": schematypeVariable, "addlSchematype": addlSchematype, "addlSchemaItemprop": addlSchemaItemprop } else: returnType = "SINGLE" newIboxDict = { "key": cleanedInfotype, "value": cleanedContent, "schema": schematypeVariable, "addlSchematype": addlSchematype, "addlSchemaItemprop": addlSchemaItemprop } # Render the infobox HTML container and return it newIboxHTML = render_to_string( 'enterlink/ajax_infobox_singlet.html', { 'returnType': returnType, 'newIboxDict': newIboxDict, 'pluralPackages': pluralPackages, }) return JsonResponse({"type": returnType, "htmlblock": newIboxHTML})
def AJAX_Add_New_Link(request): from enterlink.media_functions import getYouTubeIdIfPresent # Get the POST variables pageSlug = request.POST['pageSlug'] option = request.POST['group1'] citeHTML = request.POST['citeHTML'] URLComment = request.POST['nl_linkcomment'] # Make sure an empty description was not provided placeholderPresent = any(placeholder in URLComment for placeholder in PLACEHOLDER_LIST) if (placeholderPresent or URLComment.strip() == "" or URLComment is None or URLComment == "<br data-mce-bogus=\"1\">"): return HttpResponse("ERROR_NO_DESCRIPTION") else: pass URLComment = badLinkSanitizer(URLComment) # Get and format the UTC timestamp timestamp = datetime.datetime.utcnow() timestamp = pytz.utc.localize(timestamp).strftime( '%m/%d/%Y %I:%M:%S %p %Z') # Get the article object from the URL slug provided cleanedParamList = getTheArticleObject(pageSlug) pageSlug = cleanedParamList[0] articleObject = cleanedParamList[1] # Parse all the current citations for the article. # This will be used later for things such as finding duplicates and getting the citation number theSoup = BeautifulSoup(citeHTML, "html5lib") resultDictionary = {} parseTinyMCE_Citations(theSoup, resultDictionary) # Set up a blank dictionary for the new link newLinkDict = { "url": None, "thumb": None, "description": URLComment, "category": "NONE", "integer": None, "isSocial": False, "attr": None, "timestamp": timestamp, "mime": None, "attribution_url": None } # Create a list of all current citations citationList, urlList = [], [] try: for citation in resultDictionary["CITATION_OBJECTS"]: citationList.append(int(citation["integer"])) urlList.append(citation["url"]) except: pass # Calculate and set the citation number for the new link if len(citationList) == 0: citationInteger = 1 else: try: citationInteger = max(citationList) + 1 except: citationInteger = None newLinkDict["integer"] = citationInteger # Check if the new link is a file if option == 'id_file': # Get and set some variables theFile = request.FILES['file'] # Add the file to the Amazon S3 bucket and get some information about it resultPack = addMediaImage(request=request, pageID=pageSlug, theFile=theFile, fileComment=URLComment, PLACEHOLDER_LIST=PLACEHOLDER_LIST, inputMime="EMPTY") # Update the new link dictionary with information about the file newLinkDict["url"] = resultPack["url"] newLinkDict["thumb"] = resultPack["thumb"] newLinkDict["mime"] = resultPack["mime"] newLinkDict["category"] = linkCategorizer(resultPack["url"], resultPack["mime"]) # Check for duplicate links if dupeLinkDetector(newLinkDict["url"], urlList): return HttpResponse("ERROR_ALREADY_EXISTS") # Decide where to put the new link. If it is an image, video, or YouTube link, put it in the media gallery. # Otherwise, put it in the normal citation list. if newLinkDict["category"] == "NONE": newLinkHTMLBlock = render_to_string( 'enterlink/ajax_link_singlet.html', {'theLink': newLinkDict}) return JsonResponse({ "type": "NORMAL", "htmlblock": newLinkHTMLBlock }) else: newLinkHTMLBlock = render_to_string( 'enterlink/ajax_media_gallery_singlet.html', {'theLink': newLinkDict}) return JsonResponse({ "type": "MEDIA", "htmlblock": newLinkHTMLBlock }) # Check if the new link is a URL elif option == 'id_linkurl': # Get the URL and check if it is a Wikipedia link. if request.POST['linkurl']: theURL = request.POST['linkurl'] if ('wikipedia.org' in theURL): return HttpResponse("ERROR_WIKIPEDIA_LINK") else: pass else: return HttpResponse("ERROR_NO_URL") # Check for a duplicate link if dupeLinkDetector(theURL, urlList): return HttpResponse("ERROR_ALREADY_EXISTS") # Update the new link JSON data newLinkDict["url"] = theURL newLinkDict["isSocial"] = profileLinkTester(theURL)["isProfileLink"] # Check if the URL is a link to a media object isMedia = False try: # Ping the URL to see get the data and response headers mediaTest = requests.get(theURL, headers=REQUEST_HEADER, timeout=6, verify=False, stream=True) # See if the response header indicates it is a media item. If so, set isMedia to True listOfMedias = ["video", "image", "audio"] for mediaItem in listOfMedias: mediaName = u"%s/" % mediaItem if mediaName in mediaTest.headers['Content-Type']: isMedia = True break # Check for YouTube youtubeID = getYouTubeIdIfPresent(theURL) if youtubeID: isMedia = True # Analyze and process the URL if it is a media file if isMedia: # Process depending on media type if youtubeID: newLinkDict[ "thumb"] = "https://i.ytimg.com/vi/%s/hqdefault.jpg" % youtubeID newLinkDict["mime"] = "youtube" newLinkDict["category"] = "YOUTUBE" else: # Create an empty string buffer and fill it with the media file data streamObject = StringIO.StringIO() streamObject.write( mediaTest.raw.read(decode_content=False)) # Create a file in memory from the media file theFile = InMemoryUploadedFile( streamObject, None, theURL.split("?")[0].split("/")[-1], mediaTest.headers['Content-Type'], streamObject.len, None) # Add the media file to the Amazon S3 bucket and analyze the media file resultPack = addMediaImage( request=request, pageID=pageSlug, theFile=theFile, fileComment=URLComment, PLACEHOLDER_LIST=PLACEHOLDER_LIST, inputMime=mediaTest.headers['Content-Type']) # Update the new link dictionary with info about the file newLinkDict["thumb"] = resultPack["thumb"] newLinkDict["mime"] = resultPack["mime"] newLinkDict["category"] = linkCategorizer( resultPack["url"], resultPack["mime"]) # Render the new media object as an HTML block newLinkHTMLBlock = render_to_string( 'enterlink/ajax_media_gallery_singlet.html', {'theLink': newLinkDict}) return JsonResponse({ "type": "MEDIA", "htmlblock": newLinkHTMLBlock }) except Exception as e: print(str(e)) print( "Is not media, or timeout. Considering link as normal url...") # Find the thumbnail for the new link web page, if it has one from the og:image, schema, etc. theThumbURL = fetchMetaThumbnail(request, theURL, articleObject.slug, articleObject.ipfs_hash_current[:10]) newLinkDict["thumb"] = theThumbURL # Render the new link as an HTML block newLinkHTMLBlock = render_to_string('enterlink/ajax_link_singlet.html', {'theLink': newLinkDict}) return JsonResponse({"type": "NORMAL", "htmlblock": newLinkHTMLBlock})
def edit(request, url_param="everipedia-blank-page-template"): # Fetch the article object from the URL parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] # Pull the article HTML from the cache hashObject = HashCache.objects.get( ipfs_hash=articleObject.ipfs_hash_current) # Check if the article is being submitted if (request.GET.get('submission') == '1'): # Get the POSTed article HTML innerHTMLBlock = request.POST.get("blurbHTML") # Clean up and canonicalize the submitted HTML innerHTMLBlock = entireArticleHTMLSanitizer(innerHTMLBlock)[5:] # Remove temporary HTML elements that were injected into the TinyMCE in order to make the page more interactive theSoup = BeautifulSoup(innerHTMLBlock, "html.parser") try: badClasses = [ 'add-row-btn', 'button-wrap', 'add-new-ibox', 'add-heading-wrap', ] for badClass in badClasses: listOfBads = theSoup.findAll(class_=badClass) for item in listOfBads: item.extract() except: pass # quickTitleNode = theSoup.findAll("h1") # print(unicode(quickTitleNode[0])) # Convert the BeautifulSoup object back into a string innerHTMLBlock = unicode(theSoup) # quickBody = theSoup.findAll(class_="blurb-wrap") # print(quickBody[0]) # raise # Render the article HTML and its wrapper as a string and save it to the variable resultHTML = render_to_string('enterlink/blockchain_article_wrap.html', { 'innerHTMLBlock': innerHTMLBlock, }) # Connect to the IPFS daemon and add the article HTML api = ipfsapi.connect('127.0.0.1', 5001) ipfs_hash_new = api.add_str(resultHTML) print("THE OFFICIAL NEW HASH IS: %s" % ipfs_hash_new) # Cache the article HTML try: hashTable = HashCache.objects.create( ipfs_hash=ipfs_hash_new, timestamp=datetime.datetime.now(tz=pytz.utc), html_blob=resultHTML, articletable=articleObject) except: return HttpResponse("NO CHANGES DETECTED!") # Set some variables ipfs_hash_old = articleObject.ipfs_hash_current ipfs_hash_grandparent = articleObject.ipfs_hash_parent # Need to switch this later. MAKE SURE TO FIX BLURB COMPARE TOO # return JsonResponse({"newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent}) return JsonResponse({ "newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent }) # Verify that submission was actually recorded on the EOS chain if (request.GET.get('verification') == '1'): # Get the IPFS hash ipfs_hash_new = request.GET.get('newIPFS') # Because the EOS get tables command does not allow string lookups, convert the IPFS hash to a 64-bit unsigned integer proposal_id = ipfs_to_uint64_trunc(ipfs_hash_new) proposalID = int(proposal_id) proposalIDPlusOne = proposalID + 1 # Prepare the JSON for the get table API call jsonDict = { "scope": "eparticlectr", "code": "eparticlectr", "table": "propstbl", "key_type": "i64", "index_position": "3", "lower_bound": proposalID, "upper_bound": proposalIDPlusOne, "json": "true" } # Make the API request and parse the JSON into a variable # page = requests.post('https://mainnet.libertyblock.io:7777/v1/chain/get_table_rows', headers=REQUEST_HEADER, timeout=10, verify=False, json=jsonDict) page = requests.post( 'https://nodes.get-scatter.com:443/v1/chain/get_table_rows', headers=REQUEST_HEADER, timeout=10, verify=False, json=jsonDict) json_data = json.loads(page.text) # Get the status of the proposal proposalStatus = json_data['rows'][0]['status'] # Make sure the proposal is actually recorded on-chain try: if (proposalStatus != 0): # Possibly delete the IPFS entry to prevent spamming pass except: return JsonResponse( { 'status': 'false', 'message': "NO PROPOSAL FOUND" }, status=500) # Parse some variables from the JSON proposer = json_data['rows'][0]['proposer'] currentTime = json_data['rows'][0]['starttime'] endTime = json_data['rows'][0]['endtime'] # Get the cached article HTML and parse it hashTable = HashCache.objects.get(ipfs_hash=ipfs_hash_new) parsedDict = parseBlockchainHTML(hashTable.html_blob) # Set some variables ipfs_hash_old = articleObject.ipfs_hash_current ipfs_hash_grandparent = articleObject.ipfs_hash_parent # Update the articleObject cache with data from the article HTML file (from the cache) articleObject.ipfs_hash_parent = articleObject.ipfs_hash_current articleObject.ipfs_hash_current = ipfs_hash_new articleObject.blurb_snippet = parsedDict["BLURB"] articleObject.page_type = parsedDict["PAGEMETADATA"]["page_type"] articleObject.page_title = parsedDict["PAGETITLE"] articleObject.lastmod_timestamp = timezone.now() articleObject.is_removed = parsedDict["PAGEMETADATA"]["is_removed"] articleObject.is_removed_from_index = False articleObject.is_adult_content = parsedDict["PAGEMETADATA"][ "is_adult_content"] articleObject.save() # Record the edit proposal internally. This should match all the proposals that are on-chain. EditProposal.objects.create( id=ipfs_to_uint64_trunc(ipfs_hash_new), proposed_article_hash=ipfs_hash_new, old_article_hash=ipfs_hash_old, grandparent_hash=ipfs_hash_grandparent, proposer=proposer, proposer_64t=encodeNameSwappedEndian(proposer), starttime=currentTime, endtime=endTime, status=0, article=articleObject) # Need to switch this later. MAKE SURE TO FIX BLURB COMPARE TOO # return JsonResponse({"newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent}) return JsonResponse({ "newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent }) # Temporary # if(articleObject.id < 18682257): # return HttpResponseRedirect("/editing-disabled/") if 'draft' in request.GET: account_name = request.GET.get('draft') draft = SavedDraft.objects.get(article_slug=articleObject.slug, account_name=account_name) hashObject.html_blob = draft.html_blob # Update the Django templating dictionary for the edit page contextDictionary = {} contextDictionary.update({"ARTICLE_BLOB": hashObject.html_blob}) contextDictionary.update({"ARTICLE_NAME": articleObject.page_title}) contextDictionary.update({"ARTICLE_SLUG": articleObject.slug}) contextDictionary.update({"ARTICLE_SLUG_ALT": articleObject.slug_alt}) contextDictionary.update({"ARTICLE_IS_REMOVED": articleObject.is_removed}) contextDictionary.update({"ARTICLE_PHOTO_URL": articleObject.photo_url}) contextDictionary.update( {"ARTICLE_THUMB_URL": articleObject.photo_thumb_url}) contextDictionary.update({"ARTICLE_PAGE_TYPE": articleObject.page_type}) # contextDictionary.update({"ARTICLE_PAGEVIEWS": articleObject.pageviews}) contextDictionary.update({"newlinkfileform": NewlinkFileForm()}) contextDictionary.update({"linkform": LinkForm()}) contextDictionary.update({ "pagemetaform": PageMetaForm( initial={ 'page_type': articleObject.page_type, 'sub_page_type': articleObject.page_sub_type, 'is_removed': articleObject.is_removed, 'is_adult_content': articleObject.is_adult_content }) }) # Return the HTML for the editing page return render(request, 'enterlink/edit.html', contextDictionary)
def template_handler_blockchain(request, url_param='url_param'): # Handle blank requests if ("/None" in url_param): return HttpResponse("") # Get the article object from the url parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] if(articleObject.is_removed): return HttpResponseRedirect('/error/') # See if the request is from mobile or tablet useMobile = False if (request.mobile or '/amp/' in request.path) and not request.tablet : useMobile = True # Get the last activity time lastActivityTime = articleObject.lastmod_timestamp # Get the relevant cache depending on the request type if useMobile: styledHTMLCacheTime = articleObject.mobile_cache_timestamp else: styledHTMLCacheTime = articleObject.desktop_cache_timestamp # Assume an old cache time if it is NULL, since comparing a datetime with NULL gives errors if (styledHTMLCacheTime is None): styledHTMLCacheTime = dateTimeImportClass(2000, 1, 1, 1, 1, 1, tzinfo=pytz.timezone('UTC')) useStyledHTMLCache = (lastActivityTime <= styledHTMLCacheTime) # Get the hash cache time try: hashCacheHTMLTime = HashCache.objects.get(ipfs_hash=articleObject.ipfs_hash_current).timestamp # Assume an old cache time if it is NULL, since comparing a datetime with NULL gives errors if (hashCacheHTMLTime is None): hashCacheHTMLTime = dateTimeImportClass(2000, 1, 1, 1, 1, 1, tzinfo=pytz.timezone('UTC')) except: hashCacheHTMLTime = dateTimeImportClass(2000, 1, 1, 1, 1, 1, tzinfo=pytz.timezone('UTC')) # Detect the incoming language incomingLanguage = translation.get_language() # Determine whether to pull the cached CSS-stylized pages from Azure blob storage, or to generate new ones if useStyledHTMLCache == True: # Determing to pull either the mobile or desktop / tablet pages if useMobile: fetchURL = 'https://epcdndisk.blob.core.windows.net/mobile-template-blockchain/%s.html.gz' % (articleObject.ipfs_hash_current) else: fetchURL = 'https://epcdndisk.blob.core.windows.net/desktop-template-blockchain/%s.html.gz' % (articleObject.ipfs_hash_current) # Fetch the cached page response = urllib2.urlopen(fetchURL) # Read the page and unzip it responseNugget = response.read() content = gzip.GzipFile(fileobj=StringIO.StringIO(responseNugget)).read() # Return the HTML response = HttpResponse(content) return response else: # Set the user as anonymous request.user = AnonymousUser() # Fetch the language that the article was created in renderLang = articleObject.page_lang # Set the session language to the page language. This is temporary so the page is generated with the correct language request = nonPOSTSetLanguage(request, renderLang) # Fetch the site notice try: # Try the language specific version theNotice = SiteNotice.objects.get(id=2, lang=renderLang) except: # Default to English if that fails theNotice = SiteNotice.objects.get(id=2, lang="en") # Get the raw, unstyled HTML for the page unstyledHTML = get_article_raw_html(ipfs_hash=articleObject.ipfs_hash_current, lastactivity=lastActivityTime, articletable=articleObject ) if useMobile: # Parse the HTML for relevant data newDictionary = parseBlockchainHTML(unstyledHTML, useAMP=True) # Set some variables newDictionary.update({"CURRENT_IPFS_HASH": articleObject.ipfs_hash_current}) newDictionary.update({"LANG_OVERRIDE": renderLang}) newDictionary.update({'SITE_NOTICE': theNotice.mobile_html}) newDictionary.update({'IS_REMOVED_FROM_INDEX': articleObject.is_removed_from_index}) newDictionary.update({'CURRENT_PAGEVIEWS': articleObject.pageviews}) # Generate the CSS-styled page from the template, filling in variables parsed from the unstyled/raw HTML styledHTMLResponse = render(request, 'enterlink/template_blockchain_styled_amp.html', newDictionary) # Store the CSS-styled mobile page to Azure blob refreshTemplateCacheBlockchain(articleObject.ipfs_hash_current, styledHTMLResponse.content, 'mobile-template-blockchain') # Set the cache timestamp articleObject.mobile_cache_timestamp = timezone.now() articleObject.save() else: # Parse the HTML for relevant data newDictionary = parseBlockchainHTML(unstyledHTML, useAMP=False) newDictionary.update({'SITE_NOTICE': theNotice.desktop_html}) # Set some variables newDictionary.update({"CURRENT_IPFS_HASH": articleObject.ipfs_hash_current}) newDictionary.update({"LANG_OVERRIDE": renderLang}) newDictionary.update({'IS_REMOVED_FROM_INDEX': articleObject.is_removed_from_index}) newDictionary.update({'CURRENT_PAGEVIEWS': articleObject.pageviews}) newDictionary.update({'isTemplatePage': True}) # Generate the CSS-styled page from the template, filling in variables parsed from the unstyled/raw HTML styledHTMLResponse = render(request, 'enterlink/template_blockchain_styled_desktop.html', newDictionary) # Store the CSS-styled desktop/tablet page to Azure blob refreshTemplateCacheBlockchain(articleObject.ipfs_hash_current, styledHTMLResponse.content, 'desktop-template-blockchain') # Set the cache timestamp articleObject.desktop_cache_timestamp = timezone.now() articleObject.save() # Construct a blurb snippet miniBlurb = blurbSplitter(newDictionary["BLURB"], truncateLimit=2048, miniblurb=True)[0] miniBlurb = whiteSpaceStripper(miniBlurb) # Update the article object with info from the HTML ArticleTable.objects.filter(slug__iexact=articleObject.slug).update( page_title=newDictionary["PAGETITLE"], blurb_snippet=miniBlurb, photo_url=newDictionary["PHOTOOBJECT"]["url"], photo_thumb_url=newDictionary["PHOTOOBJECT"]["thumb"], page_type=newDictionary["PAGEMETADATA"]["page_type"], page_sub_type=newDictionary["PAGEMETADATA"]["sub_page_type"], is_removed=newDictionary["PAGEMETADATA"]["is_removed"], is_removed_from_index=newDictionary["PAGEMETADATA"]["is_indexed"], bing_index_override=newDictionary["PAGEMETADATA"]["bing_index_override"], is_adult_content=newDictionary["PAGEMETADATA"]["is_adult_content"] ) # Set the pageviews if articleObject.pageviews == None: articleObject.pageviews = newDictionary["PAGEMETADATA"]["pageviews"] articleObject.save() # Set the language back to what it was before nonPOSTSetLanguage(request, incomingLanguage) # Return the HTML return styledHTMLResponse
def AJAX_Hoverlink(request, url_param): # Get the article from the url parameter cleanedParamList = getTheArticleObject(url_param) articleObject = cleanedParamList[1] # Fail if the article has been removed try: if articleObject.is_removed == True: return HttpResponseRedirect('/error/') except: pass # Determine whether to use the lightbox (if desktop or tablet) or the hover bubble (if mobile AMP) useLightBox = False if request.GET.get('lightbox') == "1": useLightBox = True # Determine which area to parse try: mediaType = request.GET.get('media_type') except: mediaType = "" # Get the link to use try: linkURL = request.GET['target_url'] linkURL = urllib.unquote_plus(linkURL) except: linkURL = "" print("LinkURL not found") # Get the cached HTML for the article cacheObject = HashCache.objects.get(ipfs_hash=articleObject.ipfs_hash_current) # Parse the HTML resultDictionary = parseBlockchainHTML(cacheObject.html_blob) # Check for YouTube youtubeResult = getYouTubeIdIfPresent(linkURL) # Get all the citations from the parsed article and loop through them until the requested one is found # When found, save the JSON for that citation citationObject = "" for citation in resultDictionary["CITATION_OBJECTS"]: if citation["url"] == linkURL: citationObject = citation break if youtubeResult: if youtubeResult in citation["url"]: citationObject = citation break # Fill the Django template context with relevant data from both the article... contextDictionary = {} contextDictionary.update({"ARTICLE_NAME": articleObject.page_title}) contextDictionary.update({"ARTICLE_SLUG": articleObject.slug}) contextDictionary.update({"ARTICLE_SLUG_ALT": articleObject.slug_alt}) contextDictionary.update({"ARTICLE_IS_REMOVED": articleObject.is_removed}) contextDictionary.update({"ARTICLE_PHOTO_URL": articleObject.photo_url}) contextDictionary.update({"ARTICLE_THUMB_URL": articleObject.photo_thumb_url}) contextDictionary.update({"ARTICLE_PAGE_TYPE": articleObject.page_type}) contextDictionary.update({"BLURB_SNIPPET": articleObject.blurb_snippet}) # ... and the citation JSON try: # Try the main citations first contextDictionary.update({"CITATION_DESCRIPTION": citationObject["description"]}) contextDictionary.update({"CITATION_TIMESTAMP": citationObject["timestamp"]}) contextDictionary.update({"CITATION_URL": citationObject["url"]}) contextDictionary.update({"CITATION_THUMB": citationObject["thumb"]}) contextDictionary.update({"CITATION_MIME": citationObject["mime"]}) contextDictionary.update({"CITATION_CATEGORY": citationObject["category"]}) contextDictionary.update({"CITATION_YOUTUBE_ID": youtubeResult}) except: # Otherwise try the media ones mediaObject = "" for mediaItem in resultDictionary["MEDIA_OBJECTS"]: # print(mediaItem) # print(linkURL) if mediaItem["url"] == linkURL or mediaItem["thumb"] == linkURL: mediaObject = mediaItem break if youtubeResult: if youtubeResult in mediaItem["url"]: mediaObject = mediaItem break contextDictionary.update({"CITATION_DESCRIPTION": mediaObject["caption"]}) contextDictionary.update({"CITATION_TIMESTAMP": mediaObject["timestamp"]}) contextDictionary.update({"CITATION_URL": mediaObject["url"]}) contextDictionary.update({"CITATION_THUMB": mediaObject["thumb"]}) contextDictionary.update({"CITATION_MIME": mediaObject["mime"]}) contextDictionary.update({"CITATION_CATEGORY": mediaObject["class"]}) contextDictionary.update({"CITATION_YOUTUBE_ID": youtubeResult}) # Render the hoverlink bubble appropriately if (useLightBox): # Desktop and Tablet return render(request, "enterlink/hoverlink_iframe_blockchain.html", contextDictionary) else: # Mobile return render(request, 'enterlink/hoverlink_ajax_blockchain.html', contextDictionary)
def edit(request, url_param="everipedia-blank-page-template", lang_param=""): MERGED_FROM_HASH = "" # Pull the article HTML from the cache if "from_hash" in request.GET: fromHash = request.GET.get("from_hash") toHash = request.GET.get("to_hash") if toHash == "": return HttpResponseRedirect(u"/wiki/lang_%s/%s/edit/" % (lang_param, url_param)) MERGED_FROM_HASH = fromHash # Fetch the article object from the URL parameter cleanedParamList = getTheArticleObject(toHash) articleObject = cleanedParamList[1] if articleObject.slug != url_param and articleObject.slug_alt != url_param: return HttpResponseRedirect( u"/wiki/lang_%s/%s/edit/?from_hash=%s&to_hash=%s" % (articleObject.page_lang, articleObject.slug, fromHash, toHash)) blobHTML = merge_page(fromHash, toHash) else: # Fetch the article object from the URL parameter cleanedParamList = getTheArticleObject(url_param, passedLang=lang_param) articleObject = cleanedParamList[1] hashObject = HashCache.objects.get( ipfs_hash=articleObject.ipfs_hash_current) blobHTML = hashObject.html_blob # Check if the article is being submitted if (request.GET.get('submission') == '1'): # Get the POSTed article HTML innerHTMLBlock = request.POST.get("blurbHTML") # Clean up and canonicalize the submitted HTML. innerHTMLBlock = entireArticleHTMLSanitizer(innerHTMLBlock) # Remove temporary HTML elements that were injected into the TinyMCE in order to make the page more interactive theSoup = BeautifulSoup(innerHTMLBlock, "html.parser") try: badClasses = [ 'add-row-btn', 'button-wrap', 'add-new-ibox', 'add-heading-wrap', ] for badClass in badClasses: listOfBads = theSoup.findAll(class_=badClass) for item in listOfBads: item.extract() except: pass # Update the timestamp theTimeStamp = unicode(datetime.datetime.now(tz=pytz.utc)) modTimeParent = theSoup.find_all("tr", attrs={"data-key": "last_modified"}) modTimeTds = modTimeParent[0].find_all("td") modTimeTds[1].string = theTimeStamp # quickTitleNode = theSoup.findAll("h1") # print(unicode(quickTitleNode[0])) # Convert the BeautifulSoup object back into a string innerHTMLBlock = unicode(theSoup) # quickBody = theSoup.findAll(class_="blurb-wrap") # print(quickBody[0]) # raise # Render the article HTML and its wrapper as a string and save it to the variable resultHTML = render_to_string('enterlink/blockchain_article_wrap.html', { 'innerHTMLBlock': innerHTMLBlock, }) # Connect to the IPFS daemon and add the article HTML api = ipfsapi.connect('127.0.0.1', 5001) ipfs_hash_new = api.add_str(resultHTML) print("THE OFFICIAL NEW HASH IS: %s" % ipfs_hash_new) # Cache the article HTML try: hashTable = HashCache.objects.create(ipfs_hash=ipfs_hash_new, timestamp=theTimeStamp, html_blob=resultHTML, articletable=articleObject) except: return HttpResponse("NO CHANGES DETECTED!") # Set some variables ipfs_hash_old = articleObject.ipfs_hash_current ipfs_hash_grandparent = articleObject.ipfs_hash_parent # Need to switch this later. MAKE SURE TO FIX BLURB COMPARE TOO # return JsonResponse({"newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent}) return JsonResponse({ "newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent }) # Verify that submission was actually recorded on the EOS chain if (request.GET.get('verification') == '1'): # Get the IPFS hash ipfs_hash_new = request.GET.get('newIPFS') MERGED_FROM_HASH = request.GET.get('merged_from_hash') if MERGED_FROM_HASH != "": mergeSourceArticle = ArticleTable.objects.get( ipfs_hash_current=MERGED_FROM_HASH) mergeSourceArticle.is_removed = 1 mergeSourceArticle.redirect_page_id = articleObject.id mergeSourceArticle.save() # print("BEEEE %s" % MERGED_FROM_HASH) # Because the EOS get tables command does not allow string lookups, convert the IPFS hash to a 64-bit unsigned integer proposal_id = ipfs_to_uint64_trunc(ipfs_hash_new) proposalID = int(proposal_id) proposalIDPlusOne = proposalID + 1 # This errors out more often than it prevents bad submissions so I've commented it out - Kedar ## Prepare the JSON for the get table API call #jsonDict = {"scope": "eparticlectr", "code": "eparticlectr", "table": "propstbl", "key_type": "i64", # "index_position": "3", "lower_bound": proposalID, "upper_bound": proposalIDPlusOne, "json": "true"} ## Make the API request and parse the JSON into a variable #count = 0 #while count < 5: # # page = requests.post('https://mainnet.libertyblock.io:7777/v1/chain/get_table_rows', headers=REQUEST_HEADER, timeout=10, verify=False, json=jsonDict) # page = requests.post('https://proxy.eosnode.tools/v1/chain/get_table_rows', headers=REQUEST_HEADER, timeout=10, verify=False, json=jsonDict) # if 200 <= page.status_code <= 299: # json_data = json.loads(page.text) # break # else: # # Sleep for 1sec and try again # print("EOS API hit failed. Trying again in 500ms.") # time.sleep(1) # count += 1 ## Get the status of the proposal #proposalStatus = json_data['rows'][0]['status'] ## Make sure the proposal is actually recorded on-chain #try: # if (proposalStatus != 0): # # Possibly delete the IPFS entry to prevent spamming # pass #except: # return JsonResponse({'status': 'false', 'message': "NO PROPOSAL FOUND"}, status=500) # Parse some variables from the JSON proposer = request.GET.get('proposer') currentTime = int(time.time()) endTime = currentTime + 6 * 3600 # Get the cached article HTML and parse it hashTable = HashCache.objects.get(ipfs_hash=ipfs_hash_new) parsedDict = parseBlockchainHTML(hashTable.html_blob, articleObj=articleObject) # Set some variables ipfs_hash_old = articleObject.ipfs_hash_current ipfs_hash_grandparent = articleObject.ipfs_hash_parent miniBlurb = blurbSplitter(parsedDict["BLURB"], 2048, minimizeHTML=True)[0] miniBlurb = whiteSpaceStripper(miniBlurb) # Update the articleObject cache with data from the article HTML file (from the cache) articleObject.ipfs_hash_parent = articleObject.ipfs_hash_current articleObject.ipfs_hash_current = ipfs_hash_new articleObject.blurb_snippet = miniBlurb articleObject.page_type = ( None if parsedDict["PAGEMETADATA"]["page_type"] == "None" else parsedDict["PAGEMETADATA"]["page_type"]) articleObject.page_title = parsedDict["PAGETITLE"] articleObject.lastmod_timestamp = timezone.now() articleObject.is_removed = parsedDict["PAGEMETADATA"]["is_removed"] articleObject.is_removed_from_index = False articleObject.is_adult_content = parsedDict["PAGEMETADATA"][ "is_adult_content"] articleObject.page_lang = parsedDict["PAGEMETADATA"]["page_lang"] articleObject.save() # Update the index updateElasticsearch(articleObject, u"PAGE_UPDATED_OR_CREATED") # Record the edit proposal internally. This should match all the proposals that are on-chain. EditProposal.objects.create( id=ipfs_to_uint64_trunc(ipfs_hash_new), proposed_article_hash=ipfs_hash_new, old_article_hash=ipfs_hash_old, grandparent_hash=ipfs_hash_grandparent, proposer=proposer, proposer_64t=encodeNameSwappedEndian(proposer), starttime=currentTime, endtime=endTime, status=0, article=articleObject) # Need to switch this later. MAKE SURE TO FIX BLURB COMPARE TOO # return JsonResponse({"newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent}) return JsonResponse({ "newIPFS": ipfs_hash_new, "oldIPFS": ipfs_hash_old, "grandparentIPFS": ipfs_hash_grandparent }) # Temporary # if(articleObject.id < 18682257): # return HttpResponseRedirect("/editing-disabled/") if 'draft' in request.GET: account_name = request.GET.get('draft') draft = SavedDraft.objects.get(article_slug=articleObject.slug, account_name=account_name) hashObject.html_blob = draft.html_blob formattedArticleBlob = prettifyCorrector(blobHTML) formattedArticleBlob = editorStructureCorrector(blobHTML, passedLang=lang_param) # print(formattedArticleBlob) # Update the Django templating dictionary for the edit page contextDictionary = {} contextDictionary.update({"ARTICLE_BLOB": formattedArticleBlob}) contextDictionary.update({"ARTICLE_NAME": articleObject.page_title}) contextDictionary.update({"PAGE_LANG": articleObject.page_lang}) contextDictionary.update({"ARTICLE_SLUG": articleObject.slug}) contextDictionary.update({"ARTICLE_SLUG_ALT": articleObject.slug_alt}) contextDictionary.update({"ARTICLE_IS_REMOVED": articleObject.is_removed}) contextDictionary.update({"ARTICLE_PHOTO_URL": articleObject.photo_url}) contextDictionary.update( {"ARTICLE_THUMB_URL": articleObject.photo_thumb_url}) contextDictionary.update({"ARTICLE_PAGE_TYPE": articleObject.page_type}) contextDictionary.update({"ARTICLE_LANG": articleObject.page_lang}) contextDictionary.update( {"ARTICLE_CURRENT_HASH": articleObject.ipfs_hash_current}) contextDictionary.update({"MERGED_FROM_HASH": MERGED_FROM_HASH}) contextDictionary.update({"newlinkfileform": NewlinkFileForm()}) contextDictionary.update({"linkform": LinkForm()}) contextDictionary.update({ "pagemetaform": PageMetaForm( initial={ 'page_type': articleObject.page_type, 'sub_page_type': articleObject.page_sub_type, 'is_removed': articleObject.is_removed, 'is_adult_content': articleObject.is_adult_content, 'page_lang': articleObject.page_lang }) }) # Return the HTML for the editing page return render(request, 'enterlink/edit.html', contextDictionary)
def merge_page(from_ipfs, to_ipfs): # Need some sort of auth here # The merge should refresh the page with the combined stuff added in, then force it through Scatter # Basically, run parseBlockchainHTML on both pages, combine the JSONs, then create a new page # Merge might need a separate screen # Get the article objects cleanedParamList1 = getTheArticleObject(from_ipfs) cleanedParamList2 = getTheArticleObject(to_ipfs) articleObjectFrom = cleanedParamList1[1] articleObjectTo = cleanedParamList2[1] # Pull the article HTMLs from the cache hashObjectFrom = HashCache.objects.get(ipfs_hash=from_ipfs) hashObjectTo = HashCache.objects.get(ipfs_hash=to_ipfs) # Create the soups try: fromSoup = BeautifulSoup( hashObjectFrom.html_blob.decode('utf-8', 'ignore'), "html.parser") except: fromSoup = BeautifulSoup(hashObjectFrom.html_blob, "html.parser") try: toSoup = BeautifulSoup( hashObjectTo.html_blob.decode('utf-8', 'ignore'), "html.parser") except: toSoup = BeautifulSoup(hashObjectTo.html_blob, "html.parser") # Merge the blurbs fromBlurb = fromSoup.find_all("div", class_='blurb-wrap')[0] toBlurb = toSoup.find_all("div", class_='blurb-wrap')[0] toBlurb.append(fromBlurb) fromBlurb.unwrap() # Merge the galleries fromGallery = fromSoup.find_all("ul", class_='media-list')[0] toGallery = toSoup.find_all("ul", class_='media-list')[0] toGallery.append(fromGallery) fromGallery.unwrap() # Merge the references fromReferences = fromSoup.find_all("ul", class_='reference-list')[0] toReferences = toSoup.find_all("ul", class_='reference-list')[0] toReferences.append(fromReferences) fromReferences.unwrap() # Merge the nonplural infoboxes fromInfoboxes = fromSoup.find_all("table", class_='ibox-list-nonplural')[0] fromInfoboxesTD = fromInfoboxes.find_all("td")[0] fromInfoboxesContainer = fromInfoboxesTD.parent toInfoboxes = toSoup.find_all("table", class_='ibox-list-nonplural')[0] toInfoboxesTD = toInfoboxes.find_all("td")[0] toInfoboxesContainer = toInfoboxesTD.parent toInfoboxesContainer.append(fromInfoboxes) fromInfoboxesContainer.unwrap() # Merge the plural infoboxes fromInfoboxes = fromSoup.find_all("div", class_='ibox-list-plural')[0] toInfoboxes = toSoup.find_all("div", class_='ibox-list-plural')[0] toInfoboxes.append(fromInfoboxes) fromInfoboxes.unwrap() # Return the cleaned string blobString = deBeautifySoup(toSoup, skipSlice=True) return blobString