frontend login work

macdev
quadrismegistus 4 years ago
parent aefca13fe9
commit 62845661f8

@ -0,0 +1,96 @@
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.screenmanager import Screen
from kivymd.icon_definitions import md_icons
from kivymd.app import MDApp
from kivymd.uix.list import OneLineIconListItem
Builder.load_string(
'''
#:import images_path kivymd.images_path
<CustomOneLineIconListItem>:
IconLeftWidget:
icon: root.icon
<PreviousMDIcons>:
BoxLayout:
orientation: 'vertical'
spacing: dp(10)
padding: dp(20)
BoxLayout:
size_hint_y: None
height: self.minimum_height
MDIconButton:
icon: 'magnify'
MDTextField:
id: search_field
hint_text: 'Search icon'
on_text: root.set_list_md_icons(self.text, True)
RecycleView:
id: rv
key_viewclass: 'viewclass'
key_size: 'height'
RecycleBoxLayout:
padding: dp(10)
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
'''
)
class CustomOneLineIconListItem(OneLineIconListItem):
icon = StringProperty()
class PreviousMDIcons(Screen):
def set_list_md_icons(self, text="", search=False):
'''Builds a list of icons for the screen MDIcons.'''
def add_icon_item(name_icon):
self.ids.rv.data.append(
{
"viewclass": "CustomOneLineIconListItem",
"icon": name_icon,
"text": name_icon,
"callback": lambda x: x,
}
)
self.ids.rv.data = []
for name_icon in md_icons.keys():
if search:
if text in name_icon:
add_icon_item(name_icon)
else:
add_icon_item(name_icon)
class MainApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = PreviousMDIcons()
def build(self):
return self.screen
def on_start(self):
self.screen.set_list_md_icons()
MainApp().run()

@ -2,8 +2,12 @@
# change this to your external ip address for your server
#(needs to be external to allow tor routing)
DEFAULT_SCREEN='feed'
HORIZONTAL = False
WINDOW_SIZE = (1136,640) if HORIZONTAL else (640,1136)
import random
HORIZONTAL = random.choice([True,True,True,False])
FACTOR=1
WINDOW_SIZE = (1136*FACTOR,640*FACTOR) if HORIZONTAL else (640*FACTOR,1136*FACTOR)
# monkeypatching the things that asyncio needs
import subprocess
@ -257,35 +261,39 @@ class MainApp(MDApp):
def login(self,un=None,pw=None):
dat = self.api.login(un,pw)
self.log(dat)
if 'success' in dat:
self.save_login(un)
elif 'error' in dat:
self.root.ids.login_screen.login_status.text=dat['error']
return False
def register(self,un,pw):
dat = self.api.register(un,pw)
if 'success' in dat:
self.save_login(un)
return True
elif 'error' in dat:
self.root.ids.login_screen.login_status.text=dat['error']
async def do():
dat = await self.api.login(un,pw)
self.log(dat)
if 'success' in dat:
self.save_login(un)
elif 'error' in dat:
self.root.ids.login_screen.login_status.text=dat['error']
return False
asyncio.create_task(do())
def upload(self,filename,file_id=None):
def register(self,un,pw):
async def do():
dat = await self.api.register(un,pw)
if 'success' in dat:
self.save_login(un)
return True
elif 'error' in dat:
self.root.ids.login_screen.login_status.text=dat['error']
return False
asyncio.create_task(do())
async def upload(self,filename,file_id=None):
self.log('uploading filename:',filename)
rdata=self.api.upload(filename,file_id=file_id)
rdata=await self.api.upload(filename,file_id=file_id)
self.log('upload result:',rdata)
if rdata is not None:
rdata['success']='File uploaded'
return rdata
return {'error':'Upload failed'}
def download(self,file_id,output_fn=None):
async def download(self,file_id,output_fn=None):
self.log('downloading:',file_id)
file_dat = self.api.download(file_id)
file_dat = await self.api.download(file_id)
if not output_fn:
file_id=file_dat['id']
file_ext=file_dat['ext']
@ -325,26 +333,12 @@ class MainApp(MDApp):
async def get_posts(self):
return await self.api.get_posts()
def get_my_posts(self):
return self.api.get_posts('/author/'+self.username)
def get_image(self, img_src):
# is there an image?
if not img_src: return
# is it cached?
ofn_image = os.path.join('cache','img',img_src)
if not os.path.exists(ofn_image):
# create dir?
ofn_image_dir = os.path.split(ofn_image)[0]
if not os.path.exists(ofn_image_dir): os.makedirs(ofn_image_dir)
self.log('getting image!')
with self.get_session() as sess:
with sess.get(self.api+'/download/'+img_src,stream=True) as r:
with open(ofn_image,'wb') as of:
shutil.copyfileobj(r.raw, of)
return ofn_image
async def get_my_posts(self):
return await self.api.get_posts('/author/'+self.username)
### SYNCHRONOUS?
def app_func(self):
'''This will run both methods asynchronously and then block until they
are finished
@ -361,31 +355,6 @@ class MainApp(MDApp):
return asyncio.gather(run_wrapper(), self.other_task)
async def waste_time_freely(self):
'''This method is also run by the asyncio loop and periodically prints
something.
'''
try:
i = 0
while True:
if self.root is not None:
#status = self.root.ids.label.status
status='TimeWaster'
self.log('{} on the beach'.format(status))
# # get some sleep
# if self.root.ids.btn1.state != 'down' and i >= 2:
# i = 0
# self.log('Yawn, getting tired. Going to sleep')
# self.root.ids.btn1.trigger_action()
i += 1
await asyncio.sleep(2)
except asyncio.CancelledError as e:
self.log('Wasting time was canceled', e)
finally:
# when canceled, print that it finished
self.log('Done wasting time')
if __name__ == '__main__':

@ -74,7 +74,7 @@ MyLayout:
background_palette: 'Red'
background_hue: '500'
specific_text_color: 1,0,0,1
right_action_items: [['post-outline', partial(root.change_screen, 'feed')], ['pencil-plus-outline', partial(root.change_screen, 'post')], ['message-processing-outline', partial(root.change_screen, 'messages')], ['bell-outline', partial(root.change_screen, 'notifications')], ['account-circle-outline', partial(root.change_screen, 'profile')]]
right_action_items: [['card-text-outline', partial(root.change_screen, 'feed')], ['pencil-plus-outline', partial(root.change_screen, 'post')], ['message-outline', partial(root.change_screen, 'messages')], ['bell-outline', partial(root.change_screen, 'notifications')], ['account-circle-outline', partial(root.change_screen, 'profile')]]
#left_action_items: [[f"assets/fist2.png", partial(root.change_screen, 'feed')]]
font_context: None
font_name: f'assets/Strengthen.ttf'

@ -159,7 +159,7 @@
border_radius:20
canvas:
Color:
rgba: 1,0,0,0.5
rgba: 0,0,0,0.5
Line:
width: 1
rounded_rectangle: (self.x, self.y, self.width, self.height, 20, 20, 20, 20)

@ -172,6 +172,8 @@ class FeedScreen(ProtectedScreen):
posts = ListProperty()
def on_pre_enter(self):
super().on_pre_enter()
async def go():
# self.log('ids:' +str(self.ids.post_carousel.ids))
for post in self.posts:

@ -12,16 +12,40 @@
id: loginbox
orientation:'vertical'
cols:1
size_hint:0.5,0.2
size_hint:0.5,None
pos_hint: {'center_x':0.5,'center_y':0.5}
md_bg_color: 0,0,0,1
radius:[20,]
border_radius:20
spacing:'10dp'
padding:'10dp'
padding:'25dp'
adaptive_height: True
<UsernameLayout>:
cols:2
orientation:'horizontal'
adaptive_height: True
size_hint:1,None
# pos_hint:{'right':0.9}
# spacing:'100sp'
# md_bg_color:1,1,0,1
<UsernameLabel>:
theme_text_color: 'Custom'
text_color: 1,0,0,1
# width:'100sp'
adaptive_width: True
size_hint:None,None
# md_bg_color:1,0,0,1
# pos_hint: {'y':1}
halign:'center'
<UsernameField>:
id: username
text: ""
hint_text: "username"
required: True
write_tab: False
@ -32,13 +56,14 @@
line_color_normal: 1,0,0,1
current_hint_text_color: 1,0,0,1
error_color:1,0,0,1
# pos_hint: {'x':1,'y':0.8}
# size_hint:(None,None)
pos_hint: {'center_x':0.5,'y':0.2}
size_hint:0.8,None
<PasswordField>:
id: password
text: ""
password: True
hint_text: "password"
required: True
@ -50,16 +75,21 @@
line_color_normal: 1,0,0,1
current_hint_text_color: 1,0,0,1
text_color: 1,0,0,1
# pos_hint: {'center_x':1,'y':0.8}
# size_hint:(None,None)
pos_hint: {'center_x':0.5,'y':0.2}
size_hint:0.8,None
<LoginButtonLayout>:
id: buttonbox
size_hint_y: None
orientation:'horizontal'
cols: 2
# size_hint_y: None
adaptive_width: True
height: '56dp'
spacing: '10dp'
pos_hint: {'center_x': .5}
spacing: '25dp'
padding: '10dp'
# md_bg_color:1,1,0,1
size_hint:None,None
pos_hint: {'center_x': .5}#, 'bottom':1}
<LoginButton>:
text: "login"
@ -69,6 +99,8 @@
theme_text_color: "Custom"
text_color: 1,0,0,1
md_bg_color: 0,0,0,1
size_hint:None,None
# pos_hint: {'center_x': .5, 'bottom':1}
<RegisterButton>:
text: "register"
@ -77,14 +109,18 @@
theme_text_color: "Custom"
text_color: 1,0,0,1
md_bg_color: 0,0,0,1
# size_hint:1,None
<LoginStatus>:
id: login_status
text:""
theme_text_color: 'Error'
pos_hint:{'center_x':.5}
size_hint:1,1
halign:'center'
pos_hint:{'center_x':.5, 'center_y':0.5}
<LoginScreen>:
name: "login"
id: login_screen

@ -3,6 +3,7 @@ from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.textfield import MDTextField
from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.label import MDLabel
from main import MyLabel
class LoginBoxLayout(MDBoxLayout): pass
class LoginButtonLayout(MDBoxLayout): pass
@ -12,6 +13,9 @@ class LoginButton(MDRectangleFlatButton): pass
class RegisterButton(MDRectangleFlatButton): pass
class LoginStatus(MDLabel): pass
class UsernameLayout(MDBoxLayout): pass
class UsernameLabel(MDLabel): pass
class LoginScreen(BaseScreen):
#def on_pre_enter(self):
# global app
@ -21,28 +25,52 @@ class LoginScreen(BaseScreen):
#log(self.ids)
#log('hello?')
self.layout = LoginBoxLayout()
self.layout_username = UsernameLayout()
self.label_username = UsernameLabel(text="username:")
self.username_field = UsernameField()
self.username_field.line_color_focus=(1,0,0,1)
self.layout.add_widget(self.username_field)
self.username_field.line_color_normal=(1,0,0,0.25)
self.username_field.font_name='assets/font.otf'
self.layout_username.add_widget(self.label_username)
self.layout_username.add_widget(self.username_field)
self.layout.add_widget(self.layout_username)
#log(self.username_field)
# self.username_field.text='hello????'
self.layout_password = UsernameLayout()
self.label_password = UsernameLabel(text='password:')
self.label_password.font_name='assets/font.otf'
self.label_username.font_name='assets/font.otf'
self.password_field = PasswordField()
self.password_field.line_color_focus=(1,0,0,1)
self.layout.add_widget(self.password_field)
self.password_field.line_color_normal=(1,0,0,0.25)
self.password_field.font_name='assets/font.otf'
self.layout_password.add_widget(self.label_password)
self.layout_password.add_widget(self.password_field)
self.layout.add_widget(self.layout_password)
self.layout_buttons = LoginButtonLayout()
self.layout.add_widget(self.layout_buttons)
self.login_button = LoginButton()
self.login_button.font_name='assets/font.otf'
self.layout_buttons.add_widget(self.login_button)
self.register_button = RegisterButton()
self.register_button.font_name='assets/font.otf'
# self.register_button =
self.layout_buttons.add_widget(self.register_button)
self.login_status = LoginStatus()
self.login_status.font_name='assets/font.otf'
self.layout.add_widget(self.login_status)

@ -56,6 +56,8 @@ class PostScreen(ProtectedScreen):
post_id = ObjectProperty()
def on_pre_enter(self):
super().on_pre_enter()
# clear
if hasattr(self,'post_status'): self.remove_widget(self.post_status)
if hasattr(self,'post_textfield'): self.post_textfield.text=''

@ -13,7 +13,7 @@ def run_command():
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
class Watcher:
DIRECTORY_TO_WATCH = os.path.join(os.path.expanduser('~'),"/github/Komrade/p2p")
DIRECTORY_TO_WATCH = os.path.join(os.path.expanduser('~'),"/github/Komrade/")
def __init__(self):
self.observer = Observer()

@ -82,7 +82,7 @@ class Api(object):
i = 0
self._node = await self.connect()
while True:
self.log(f'Node status (pulse {i}): {self._node}')
self.log(f'Node status (minute {i}): {self._node}')
# # get some sleep
# if self.root.ids.btn1.state != 'down' and i >= 2:
@ -90,8 +90,9 @@ class Api(object):
# self.log('Yawn, getting tired. Going to sleep')
# self.root.ids.btn1.trigger_action()
i += 1
await asyncio.sleep(10)
#i += 1
await asyncio.sleep(60)
# pass
except asyncio.CancelledError as e:
self.log('Wasting time was canceled', e)
finally:
@ -169,33 +170,29 @@ class Api(object):
# self.log('OH NO!',sys.getsizeof(value_json))
return await self.set(key,value_json)
def has(self,key):
return self.get(key) is not None
async def has(self,key):
val=await self.get(key)
return val is not None
## PERSONS
def get_person(self,username):
return self.get_json('/person/'+username)
async def get_person(self,username):
return await self.get_json('/person/'+username)
def set_person(self,username,public_key):
async def set_person(self,username,public_key):
pem_public_key = save_public_key(public_key,return_instead=True)
obj = {'name':username, 'public_key':pem_public_key.decode()}
self.set_json('/person/'+username,obj)
await self.set_json('/person/'+username,obj)
## Register
def register(self,name,passkey):
if not (name and passkey):
error('name and passkey not set')
return {'error':'Register failed'}
person = self.get_person(name)
if person is not None:
self.log('error! person exists')
return {'error':'Register failed'}
async def register(self,name,passkey):
if not (name and passkey): return {'error':'Name and password needed'}
person = await self.get_person(name)
if person is not None: return {'error':'Username already exists'}
private_key,public_key = new_keys(password=passkey,save=False)
pem_private_key = save_private_key(private_key,password=passkey,return_instead=True)
@ -204,36 +201,38 @@ class Api(object):
self.app_storage.put('_keys',
private=str(pem_private_key.decode()),
public=str(pem_public_key.decode())) #(private_key,password=passkey)
self.set_person(name,public_key)
await self.set_person(name,public_key)
self.log('success! Account created')
return {'success':'Account created', 'username':name}
def load_private_key(self,password):
if not self.app_storage.exists('_keys'): return None
pem_private_key=self.app_storage.get('_keys').get('private')
try:
return load_private_key(pem_private_key.encode(),password)
return {'success':load_private_key(pem_private_key.encode(),password)}
except ValueError as e:
self.log('!!',e)
return None
return {'error':'Incorrect password'}
## LOGIN
def login(self,name,passkey):
async def login(self,name,passkey):
# verify input
if not (name and passkey):
return {'error':'Name and password required'}
# try to load private key
private_key = self.load_private_key(passkey)
if private_key is None:
return {'error':'You have never registered on this device'}
private_key_dat = self.load_private_key(passkey)
if 'error' in private_key_dat:
return {'error':private_key_dat['error']}
if not 'success' in private_key_dat:
return {'error':'Incorrect password?'}
private_key = private_key_dat['success']
# see if user exists
person = self.get_person(name)
person = await self.get_person(name)
self.log(person)
if person is None:
return {'error':'Login failed'}
@ -247,7 +246,7 @@ class Api(object):
#log('REAL PUBLIC',real_public_key.public_numbers())
if public_key.public_numbers() != real_public_key.public_numbers():
return {'error':'keys do not match!'}
return {'error':'Keys do not match!'}
return {'success':'Login successful', 'username':name}
async def append_json(self,key,data):
@ -258,7 +257,7 @@ class Api(object):
return {'success':'Length increased to %s' % len(new)}
return {'error':'Could not append json'}
def upload(self,filename,file_id=None, uri='/file/',uri_part='/part/'):
async def upload(self,filename,file_id=None, uri='/file/',uri_part='/part/'):
import sys
if not file_id: file_id = get_random_id()
@ -280,7 +279,7 @@ class Api(object):
if len(parts)>=buffer_size:
self.log('setting...')
self.set(part_keys,parts)
await self.set(part_keys,parts)
part_keys=[]
PARTS+=parts
parts=[]
@ -288,26 +287,26 @@ class Api(object):
# set all parts
#self.set(part_keys,PARTS)
self.log('# parts:',len(PARTS))
if parts and part_keys: self.set(part_keys, parts)
if parts and part_keys: await self.set(part_keys, parts)
# how many parts?
self.log('# pieces!',len(part_ids))
file_store = {'ext':os.path.splitext(filename)[-1][1:], 'parts':part_ids}
self.log('FILE STORE??',file_store)
self.set_json(uri+file_id,file_store)
await self.set_json(uri+file_id,file_store)
# file_store['data'].seek(0)
file_store['id']=file_id
return file_store
def download(self,file_id):
file_store = self.get_json('/file/'+file_id)
async def download(self,file_id):
file_store = await self.get_json('/file/'+file_id)
if file_store is None: return
self.log('file_store!?',file_store)
keys = ['/part/'+x for x in file_store['parts']]
pieces = self.get(keys)
pieces = await self.get(keys)
file_store['parts_data']=pieces
return file_store
@ -342,160 +341,25 @@ class Api(object):
## CREATE
## func
def bytes_from_file(filename,chunksize=8192):
with open(filename, 'rb') as f:
while True:
piece = f.read(chunksize)
if not piece:
break
yield piece
def get_random_id():
import uuid
return uuid.uuid4().hex
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def get_random_filename(filename):
import uuid
fn=uuid.uuid4().hex
return (fn[:3],fn[3:]+os.path.splitext(filename)[-1])
def upload():
files = request.files
# check if the post request has the file part
if 'file' not in request.files:
return {'error':'No file found'},status.HTTP_204_NO_CONTENT
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
print('filename!',file.filename)
if file.filename == '':
return {'error':'No filename'},status.HTTP_206_PARTIAL_CONTENT
if file and allowed_file(file.filename):
print('uploading file...')
#prefix,filename = get_random_filename(file.filename) #secure_filename(file.filename)
#odir = os.path.join(app.config['UPLOAD_DIR'], os.path.dirname(filename))
#if not os.path.exists(odir):
ext = os.path.splitext(file.filename)[-1]
media = Media(ext=ext).save()
uid = media.uid
filename = media.filename
prefix,fn=filename.split('/')
folder = os.path.join(app.config['UPLOAD_DIR'], prefix)
if not os.path.exists(folder): os.makedirs(folder)
file.save(os.path.join(folder, fn))
#return redirect(url_for('uploaded_file', filename=filename))
return {'media_uid':uid, 'filename':filename}, status.HTTP_200_OK
return {'error':'Upload failed'},status.HTTP_406_NOT_ACCEPTABLE
def download(prefix, filename):
filedir = os.path.join(app.config['UPLOAD_DIR'], prefix)
print(filedir, filename)
return send_from_directory(filedir, filename)
### READ
def get_followers(name=None):
person = Person.match(G, name).first()
data = [p.data for p in person.followers]
return jsonify(data)
def get_follows(name=None):
person = Person.match(G, name).first()
data = [p.data for p in person.follows]
return jsonify(data)
def get_posts(name=None):
if name:
person = Person.nodes.get_or_none(name=name)
data = [p.data for p in person.wrote.all()] if person is not None else []
else:
data = [p.data for p in Post.nodes.order_by('-timestamp')]
# print(data)
return jsonify({'posts':data})
def get_post(id=None):
post = Post.match(G, int(id)).first()
data = post.data
return jsonify(data)
import sys
# def bytes_from_file(filename, chunksize=8192//2):
# with open(filename, "rb") as f:
# while True:
# chunk = f.read(chunksize)
# if chunk:
# self.log(type(chunk), sys.getsizeof(chunk))
# yield chunk
# #yield from chunk
# else:
# break
# def bytes_from_file(filename,chunksize=8192):
# with open(filename,'rb') as f:
# barray = bytearray(f.read())
# for part in barray[0:-1:chunksize]:
# self.log('!?',part)
# yield bytes(part)
def bytes_from_file(filename,chunksize=8192):
with open(filename, 'rb') as f:
while True:
piece = f.read(chunksize)
if not piece:
break
yield piece
# import sys
# def bytes_from_file(path,chunksize=8000):
# ''' Given a path, return an iterator over the file
# that lazily loads the file.
# '''
# path = Path(path)
# bufsize = get_buffer_size(path)
# with path.open('rb') as file:
# reader = partial(file.read1, bufsize)
# for chunk in iter(reader, bytes()):
# _bytes=bytearray()
# for byte in chunk:
# #if _bytes is None:
# # _bytes=byte
# #else:
# _bytes.append(byte)
# if sys.getsizeof(_bytes)>=8192:
# yield bytes(_bytes) #.bytes()
# _bytes=bytearray()
# if _bytes:
# yield bytes(_bytes)
# def get_buffer_size(path):
# """ Determine optimal buffer size for reading files. """
# st = os.stat(path)
# try:
# bufsize = st.st_blksize # Available on some Unix systems (like Linux)
# except AttributeError:
# bufsize = io.DEFAULT_BUFFER_SIZE
# return bufsize
def test_api():
api = Api()

Binary file not shown.
Loading…
Cancel
Save