forked from indymedia/epicyon
Selecting profile images
parent
f5da898007
commit
52a4d17512
122
daemon.py
122
daemon.py
|
@ -69,6 +69,7 @@ from webinterface import htmlFollowConfirm
|
||||||
from webinterface import htmlSearch
|
from webinterface import htmlSearch
|
||||||
from webinterface import htmlUnfollowConfirm
|
from webinterface import htmlUnfollowConfirm
|
||||||
from webinterface import htmlProfileAfterSearch
|
from webinterface import htmlProfileAfterSearch
|
||||||
|
from webinterface import htmlEditProfile
|
||||||
from shares import getSharesFeedForPerson
|
from shares import getSharesFeedForPerson
|
||||||
from shares import outboxShareUpload
|
from shares import outboxShareUpload
|
||||||
from shares import outboxUndoShareUpload
|
from shares import outboxUndoShareUpload
|
||||||
|
@ -79,6 +80,8 @@ from manualapprove import manualDenyFollowRequest
|
||||||
from manualapprove import manualApproveFollowRequest
|
from manualapprove import manualApproveFollowRequest
|
||||||
from announce import createAnnounce
|
from announce import createAnnounce
|
||||||
from announce import outboxAnnounce
|
from announce import outboxAnnounce
|
||||||
|
from content import addMentions
|
||||||
|
from media import removeMetaData
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -756,6 +759,14 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
inReplyTo=self.path.split('?replyto=')[1]
|
inReplyTo=self.path.split('?replyto=')[1]
|
||||||
self.path=self.path.split('?replyto=')[0]+'/newpost'
|
self.path=self.path.split('?replyto=')[0]+'/newpost'
|
||||||
|
|
||||||
|
# edit profile in web interface
|
||||||
|
if '/users/' in self.path and self.path.endswith('/editprofile'):
|
||||||
|
self._set_headers('text/html',cookie)
|
||||||
|
self.wfile.write(htmlEditProfile(self.server.baseDir,self.path,self.server.domain,self.server.port).encode())
|
||||||
|
self.server.GETbusy=False
|
||||||
|
return
|
||||||
|
|
||||||
|
# Various types of new post in the web interface
|
||||||
if '/users/' in self.path and \
|
if '/users/' in self.path and \
|
||||||
(self.path.endswith('/newpost') or \
|
(self.path.endswith('/newpost') or \
|
||||||
self.path.endswith('/newunlisted') or \
|
self.path.endswith('/newunlisted') or \
|
||||||
|
@ -1360,7 +1371,6 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
# send the post
|
# send the post
|
||||||
|
|
||||||
if not fields.get('message'):
|
if not fields.get('message'):
|
||||||
return -1
|
return -1
|
||||||
if fields.get('submitPost'):
|
if fields.get('submitPost'):
|
||||||
|
@ -1602,6 +1612,116 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._redirect_headers(originPathStr,cookie)
|
self._redirect_headers(originPathStr,cookie)
|
||||||
self.server.POSTbusy=False
|
self.server.POSTbusy=False
|
||||||
|
|
||||||
|
# update of profile/avatar from web interface
|
||||||
|
if authorized and self.path.endswith('/profiledata'):
|
||||||
|
if ' boundary=' in self.headers['Content-type']:
|
||||||
|
boundary=self.headers['Content-type'].split('boundary=')[1]
|
||||||
|
if ';' in boundary:
|
||||||
|
boundary=boundary.split(';')[0]
|
||||||
|
|
||||||
|
actorStr=self.path.replace('/profiledata','').replace('/editprofile','')
|
||||||
|
nickname=getNicknameFromActor(actorStr)
|
||||||
|
if not nickname:
|
||||||
|
self._redirect_headers(actorStr,cookie)
|
||||||
|
self.server.POSTbusy=False
|
||||||
|
return
|
||||||
|
length = int(self.headers['Content-length'])
|
||||||
|
postBytes=self.rfile.read(length)
|
||||||
|
msg = email.parser.BytesParser().parsebytes(postBytes)
|
||||||
|
messageFields=msg.get_payload(decode=False).split(boundary)
|
||||||
|
fields={}
|
||||||
|
filename=None
|
||||||
|
lastImageLocation=0
|
||||||
|
for f in messageFields:
|
||||||
|
if f=='--':
|
||||||
|
continue
|
||||||
|
if ' name="' in f:
|
||||||
|
postStr=f.split(' name="',1)[1]
|
||||||
|
if '"' in postStr:
|
||||||
|
postKey=postStr.split('"',1)[0]
|
||||||
|
postValueStr=postStr.split('"',1)[1]
|
||||||
|
if ';' not in postValueStr:
|
||||||
|
if '\r\n' in postValueStr:
|
||||||
|
postLines=postValueStr.split('\r\n')
|
||||||
|
postValue=''
|
||||||
|
if len(postLines)>2:
|
||||||
|
for line in range(2,len(postLines)-1):
|
||||||
|
if line>2:
|
||||||
|
postValue+='\n'
|
||||||
|
postValue+=postLines[line]
|
||||||
|
fields[postKey]=postValue
|
||||||
|
else:
|
||||||
|
# directly search the binary array for the beginning
|
||||||
|
# of an image
|
||||||
|
searchStr=b'Content-Type: image/png'
|
||||||
|
imageLocation=postBytes.find(searchStr,lastImageLocation)
|
||||||
|
filenameBase=self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'/'+postKey
|
||||||
|
if imageLocation>-1:
|
||||||
|
filename=filenameBase+'.png.temp'
|
||||||
|
else:
|
||||||
|
searchStr=b'Content-Type: image/jpeg'
|
||||||
|
imageLocation=postBytes.find(searchStr,lastImageLocation)
|
||||||
|
if imageLocation>-1:
|
||||||
|
filename=filenameBase+'.jpg.temp'
|
||||||
|
else:
|
||||||
|
searchStr=b'Content-Type: image/gif'
|
||||||
|
imageLocation=postBytes.find(searchStr,lastImageLocation)
|
||||||
|
if imageLocation>-1:
|
||||||
|
filename=filenameBase+'.gif.temp'
|
||||||
|
if filename and imageLocation>-1:
|
||||||
|
# locate the beginning of the image, after any
|
||||||
|
# carriage returns
|
||||||
|
startPos=imageLocation+len(searchStr)
|
||||||
|
for offset in range(1,8):
|
||||||
|
if postBytes[startPos+offset]!=10:
|
||||||
|
if postBytes[startPos+offset]!=13:
|
||||||
|
startPos+=offset
|
||||||
|
break
|
||||||
|
|
||||||
|
# look for the end
|
||||||
|
imageLocationEnd=postBytes.find(b'-------',imageLocation+1)
|
||||||
|
|
||||||
|
fd = open(filename, 'wb')
|
||||||
|
if imageLocationEnd>-1:
|
||||||
|
fd.write(postBytes[startPos:][:imageLocationEnd-startPos])
|
||||||
|
else:
|
||||||
|
fd.write(postBytes[startPos:])
|
||||||
|
fd.close()
|
||||||
|
removeMetaData(filename,filename.replace('.temp',''))
|
||||||
|
os.remove(filename)
|
||||||
|
lastImageLocation=imageLocation+1
|
||||||
|
|
||||||
|
actorFilename=self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'.json'
|
||||||
|
if os.path.isfile(actorFilename):
|
||||||
|
with open(actorFilename, 'r') as fp:
|
||||||
|
actorJson=commentjson.load(fp)
|
||||||
|
actorChanged=False
|
||||||
|
if fields.get('preferredNickname'):
|
||||||
|
if fields['preferredNickname']!=actorJson['preferredUsername']:
|
||||||
|
actorJson['preferredUsername']=fields['preferredNickname']
|
||||||
|
actorChanged=True
|
||||||
|
if fields.get('bio'):
|
||||||
|
if fields['bio']!=actorJson['summary']:
|
||||||
|
actorJson['summary']= \
|
||||||
|
addMentions(self.server.baseDir, \
|
||||||
|
self.server.httpPrefix, \
|
||||||
|
nickname, \
|
||||||
|
self.server.domain,fields['bio'])
|
||||||
|
actorChanged=True
|
||||||
|
if fields.get('approveFollowers'):
|
||||||
|
approveFollowers=False
|
||||||
|
if fields['approveFollowers']!='no':
|
||||||
|
approveFollowers=True
|
||||||
|
if approveFollowers!=actorJson['manuallyApprovesFollowers']:
|
||||||
|
actorJson['manuallyApprovesFollowers']=approveFollowers
|
||||||
|
actorChanged=True
|
||||||
|
if actorChanged:
|
||||||
|
with open(actorFilename, 'w') as fp:
|
||||||
|
commentjson.dump(actorJson, fp, indent=4, sort_keys=False)
|
||||||
|
self._redirect_headers(actorStr,cookie)
|
||||||
|
self.server.POSTbusy=False
|
||||||
|
return
|
||||||
|
|
||||||
# decision to follow in the web interface is confirmed
|
# decision to follow in the web interface is confirmed
|
||||||
if authorized and self.path.endswith('/searchhandle'):
|
if authorized and self.path.endswith('/searchhandle'):
|
||||||
actorStr=self.path.replace('/searchhandle','')
|
actorStr=self.path.replace('/searchhandle','')
|
||||||
|
|
|
@ -9,6 +9,7 @@ __status__ = "Production"
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
import commentjson
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
@ -25,6 +26,71 @@ from auth import createPassword
|
||||||
from like import likedByPerson
|
from like import likedByPerson
|
||||||
from announce import announcedByPerson
|
from announce import announcedByPerson
|
||||||
|
|
||||||
|
def htmlEditProfile(baseDir: str,path: str,domain: str,port: int) -> str:
|
||||||
|
"""Shows the edit profile screen
|
||||||
|
"""
|
||||||
|
pathOriginal=path
|
||||||
|
path=path.replace('/inbox','').replace('/outbox','').replace('/shares','')
|
||||||
|
nickname=getNicknameFromActor(path)
|
||||||
|
domainFull=domain
|
||||||
|
if port:
|
||||||
|
if port!=80 and port!=443:
|
||||||
|
domainFull=domain+':'+str(port)
|
||||||
|
|
||||||
|
actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json'
|
||||||
|
if not os.path.isfile(actorFilename):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
preferredNickname=nickname
|
||||||
|
bioStr=''
|
||||||
|
manuallyApprovesFollowers='checked'
|
||||||
|
with open(actorFilename, 'r') as fp:
|
||||||
|
actorJson=commentjson.load(fp)
|
||||||
|
if actorJson.get('preferredUsername'):
|
||||||
|
preferredNickname=actorJson['preferredUsername']
|
||||||
|
if actorJson.get('summary'):
|
||||||
|
bioStr=actorJson['summary']
|
||||||
|
if actorJson.get('manuallyApprovesFollowers'):
|
||||||
|
if actorJson['manuallyApprovesFollowers']:
|
||||||
|
manuallyApprovesFollowers='checked'
|
||||||
|
else:
|
||||||
|
manuallyApprovesFollowers=''
|
||||||
|
|
||||||
|
with open(baseDir+'/epicyon-profile.css', 'r') as cssFile:
|
||||||
|
newPostCSS = cssFile.read()
|
||||||
|
|
||||||
|
editProfileForm=htmlHeader(newPostCSS)
|
||||||
|
editProfileForm+= \
|
||||||
|
'<form enctype="multipart/form-data" method="POST" action="'+path+'/profiledata">' \
|
||||||
|
' <div class="vertical-center">' \
|
||||||
|
' <p class="new-post-text">Edit profile for '+nickname+'@'+domainFull+'</p>' \
|
||||||
|
' <div class="container">' \
|
||||||
|
' <input type="text" placeholder="Preferred name" name="preferredNickname" value="'+preferredNickname+'">' \
|
||||||
|
' <textarea id="message" name="bio" placeholder="Your bio..." style="height:200px">'+bioStr+'</textarea>' \
|
||||||
|
' </div>' \
|
||||||
|
' <div class="container">' \
|
||||||
|
' Avatar image' \
|
||||||
|
' <input type="file" id="avatar" name="avatar"' \
|
||||||
|
' accept=".png">' \
|
||||||
|
' <br>Background image' \
|
||||||
|
' <input type="file" id="image" name="image"' \
|
||||||
|
' accept=".png">' \
|
||||||
|
' <br>Timeline banner image' \
|
||||||
|
' <input type="file" id="banner" name="banner"' \
|
||||||
|
' accept=".png">' \
|
||||||
|
' </div>' \
|
||||||
|
' <div class="container">' \
|
||||||
|
' <input type="checkbox" name="approveFollowers" '+manuallyApprovesFollowers+'>Approve follower requests<br>' \
|
||||||
|
' </div>' \
|
||||||
|
' <div class="container">' \
|
||||||
|
' <input type="submit" name="submitProfile" value="Submit">' \
|
||||||
|
' <a href="'+pathOriginal+'"><button class="cancelbtn">Cancel</button></a>' \
|
||||||
|
' </div>'+ \
|
||||||
|
' </div>' \
|
||||||
|
'</form>'
|
||||||
|
editProfileForm+=htmlFooter()
|
||||||
|
return editProfileForm
|
||||||
|
|
||||||
def htmlGetLoginCredentials(loginParams: str,lastLoginTime: int) -> (str,str):
|
def htmlGetLoginCredentials(loginParams: str,lastLoginTime: int) -> (str,str):
|
||||||
"""Receives login credentials via HTTPServer POST
|
"""Receives login credentials via HTTPServer POST
|
||||||
"""
|
"""
|
||||||
|
@ -297,7 +363,6 @@ def htmlProfile(baseDir: str,httpPrefix: str,authorized: bool, \
|
||||||
if port:
|
if port:
|
||||||
domainFull=domain+':'+str(port)
|
domainFull=domain+':'+str(port)
|
||||||
profileDescription=profileJson['summary']
|
profileDescription=profileJson['summary']
|
||||||
profileDescription='A test description'
|
|
||||||
postsButton='button'
|
postsButton='button'
|
||||||
followingButton='button'
|
followingButton='button'
|
||||||
followersButton='button'
|
followersButton='button'
|
||||||
|
@ -322,10 +387,13 @@ def htmlProfile(baseDir: str,httpPrefix: str,authorized: bool, \
|
||||||
followApprovals=''
|
followApprovals=''
|
||||||
linkToTimelineStart=''
|
linkToTimelineStart=''
|
||||||
linkToTimelineEnd=''
|
linkToTimelineEnd=''
|
||||||
|
editProfileStr=''
|
||||||
|
actor=profileJson['id']
|
||||||
|
|
||||||
if not authorized:
|
if not authorized:
|
||||||
loginButton='<br><a href="/login"><button class="loginButton">Login</button></a>'
|
loginButton='<br><a href="/login"><button class="loginButton">Login</button></a>'
|
||||||
else:
|
else:
|
||||||
|
editProfileStr='<a href="'+actor+'/editprofile"><button class="button"><span>Edit </span></button></a>'
|
||||||
linkToTimelineStart='<a href="/users/'+nickname+'/inbox" title="Switch to timeline view" alt="Switch to timeline view">'
|
linkToTimelineStart='<a href="/users/'+nickname+'/inbox" title="Switch to timeline view" alt="Switch to timeline view">'
|
||||||
linkToTimelineEnd='</a>'
|
linkToTimelineEnd='</a>'
|
||||||
# are there any follow requests?
|
# are there any follow requests?
|
||||||
|
@ -356,11 +424,10 @@ def htmlProfile(baseDir: str,httpPrefix: str,authorized: bool, \
|
||||||
followApprovalsSection+='<button class="followDeny">Deny</button></a>'
|
followApprovalsSection+='<button class="followDeny">Deny</button></a>'
|
||||||
followApprovalsSection+='</div>'
|
followApprovalsSection+='</div>'
|
||||||
|
|
||||||
actor=profileJson['id']
|
|
||||||
profileStr= \
|
profileStr= \
|
||||||
linkToTimelineStart+ \
|
linkToTimelineStart+ \
|
||||||
' <div class="hero-image">' \
|
' <div class="hero-image">' \
|
||||||
' <div class="hero-text">' \
|
' <div class="hero-text">'+ \
|
||||||
' <img src="'+profileJson['icon']['url']+'" alt="'+nickname+'@'+domainFull+'">' \
|
' <img src="'+profileJson['icon']['url']+'" alt="'+nickname+'@'+domainFull+'">' \
|
||||||
' <h1>'+preferredName+'</h1>' \
|
' <h1>'+preferredName+'</h1>' \
|
||||||
' <p><b>@'+nickname+'@'+domainFull+'</b></p>' \
|
' <p><b>@'+nickname+'@'+domainFull+'</b></p>' \
|
||||||
|
@ -376,7 +443,8 @@ def htmlProfile(baseDir: str,httpPrefix: str,authorized: bool, \
|
||||||
' <a href="'+actor+'/followers"><button class="'+followersButton+'"><span>Followers </span>'+followApprovals+'</button></a>' \
|
' <a href="'+actor+'/followers"><button class="'+followersButton+'"><span>Followers </span>'+followApprovals+'</button></a>' \
|
||||||
' <a href="'+actor+'/roles"><button class="'+rolesButton+'"><span>Roles </span></button></a>' \
|
' <a href="'+actor+'/roles"><button class="'+rolesButton+'"><span>Roles </span></button></a>' \
|
||||||
' <a href="'+actor+'/skills"><button class="'+skillsButton+'"><span>Skills </span></button></a>' \
|
' <a href="'+actor+'/skills"><button class="'+skillsButton+'"><span>Skills </span></button></a>' \
|
||||||
' <a href="'+actor+'/shares"><button class="'+sharesButton+'"><span>Shares </span></button></a>' \
|
' <a href="'+actor+'/shares"><button class="'+sharesButton+'"><span>Shares </span></button></a>'+ \
|
||||||
|
editProfileStr+ \
|
||||||
' </center>' \
|
' </center>' \
|
||||||
'</div>'
|
'</div>'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue