Full completed project
6
android-client/bugs.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
--- Load toolbar ---
|
||||
I fixed a teams help icon issue but made a major change unaware of consequences???
|
||||
I made it so the organisation bottom item now passes the "self.page" to the teams page and occupation page on creation instead of just "self"
|
||||
This is so these pages could have access to the load_toolbar method required to refresh the help button on previous pages
|
||||
--- Load toolbar ---
|
||||
|
||||
144
android-client/data/assets/help.txt
Normal file
@@ -0,0 +1,144 @@
|
||||
[Home:START]
|
||||
(title:START)
|
||||
Home page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
This is your home page, below you will is where you will see your friends posts.
|
||||
In the top left corner is your "profile" there you will be able to see all about you, and find friends
|
||||
Next to that is yout notifications to keep you up-to-date with your colleges
|
||||
Your settings panel is in the top left and additional areas are available in the navigation panel at the bottom of the page
|
||||
(body:END)
|
||||
[Home:END]
|
||||
|
||||
[Memories:START]
|
||||
(title:START)
|
||||
Memories page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here is where you will see your own historical posts. This means posts from previous days.
|
||||
Just select a month and then the day of the month and you will see your old post. You can still like
|
||||
and comment on it but others will not be able to see these interactions.
|
||||
(body:END)
|
||||
[Memories:END]
|
||||
|
||||
[Organisation:START]
|
||||
(title:START)
|
||||
Organisation page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you will see the navigation to your teams panel, and soon some infomation about your organisations
|
||||
Your teams panel is where you will be able to see all about your team.
|
||||
|
||||
You can only be part of one organisation, since your account is specifically tied to it.
|
||||
(body:END)
|
||||
[Organisation:END]
|
||||
|
||||
[Organisation-admin:START]
|
||||
(title:START)
|
||||
Organisation page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you will see the navigation to your teams panel, and soon some infomation about your organisations
|
||||
Your teams panel is where you will be able to see all about your team.
|
||||
Additionally since your are management/admin staff you can see the occupation area here you can accept and reject occupation change requests, create new occupations and edit or delete current ones.
|
||||
(body:END)
|
||||
[Organisation-admin:END]
|
||||
|
||||
[Profile:START]
|
||||
(title:START)
|
||||
Profile page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
This page you can see all the infomation about the profile your viewing. For your own profile you should see edit buttons next to some of infomation this means you can change or request to change this info.
|
||||
|
||||
Your role is simply how you describe your role in your team for instance "assistant"
|
||||
Your occupation determines what team you are put into, you can only be part of 1 team at a time.
|
||||
(body:END)
|
||||
[Profile:END]
|
||||
|
||||
[Notifications:START]
|
||||
(title:START)
|
||||
Notifications page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you will see notifications from your organisations admins and management, as well notifications about people interacting with your posts and when its time to make your post.
|
||||
(body:END)
|
||||
[Notifications:END]
|
||||
|
||||
[Settings:START]
|
||||
(title:START)
|
||||
Settings page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
This is where you can configure some options, for instance to stop seeing these help buttons toggle "Help Dialogs".
|
||||
(body:END)
|
||||
[Settings:END]
|
||||
|
||||
[Team:START]
|
||||
(title:START)
|
||||
Teams page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Your sorted into a team via your occupation, each occupation will have a team associated with it.
|
||||
People in the same team as you will see your posts and you will see theres. This means you will see posts from
|
||||
your team alongside posts from your friends.
|
||||
|
||||
Team leaders act as the moderator for the team. This means they can delete your posts and comments even if your
|
||||
commenting on your friends posts.
|
||||
(body:END)
|
||||
[Team:END]
|
||||
|
||||
[Occupation:START]
|
||||
(title:START)
|
||||
Occupations page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you can change edit and delete the occupations in your organisation, this panel is only available for management and admins.
|
||||
You can also approve and deny occupation change requests here. For a member to change their occupation they have to submit an occupation change request including what occupation they want to switch to. This request must be approved by management or above. Once approved the member is switched to their new team.
|
||||
(body:END)
|
||||
[Occupation:END]
|
||||
|
||||
[Friends:START]
|
||||
(title:START)
|
||||
Friends page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
In BeOpen you dont follow people but friend people, this means both people accepted to be friends with eachother. Meaning you both see eachothers posts in your feed.
|
||||
On this page you will be able to see your current friends and remove them if wanted. On the requests page (button below) you can send new friend requests, and approve or deny current friend requests. On that page is also a list of recomended friends based on mutal friends.
|
||||
|
||||
To send a friend request to someone (who isnt in the recomended) type their username into the request box, their username has to match exactly.
|
||||
(body:END)
|
||||
[Friends:END]
|
||||
|
||||
[Camera:START]
|
||||
(title:START)
|
||||
Making a post
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
You will be able to make one of these posts once a day, you will see the countdown at the top this is how long you have to post. After this time has run out you will not be able to post for that day.
|
||||
To make a post just take a picture of whatever your doing right now and head onto the next screen.
|
||||
(body:END)
|
||||
[Camera:END]
|
||||
|
||||
[PostReview:START]
|
||||
(title:START)
|
||||
Making a post
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you can review the image you just took and retake it if needed.
|
||||
You can also add a caption to your post, note that you cannot edit a post after its been created you can however delete it. So be sure this is what you want to post today since deleting means you will have to wait till tomorrow to post again.
|
||||
When your ready just hit post!
|
||||
(body:END)
|
||||
[PostReview:END]
|
||||
BIN
android-client/data/assets/profile.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
android-client/data/database.db
Normal file
BIN
android-client/data/images-temp/image1.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/images-temp/image10.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/images-temp/image11.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/images-temp/image2.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
android-client/data/images-temp/image3.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
android-client/data/images-temp/image4.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
android-client/data/images-temp/image5.jpg
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
android-client/data/images-temp/image6.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/images-temp/image7.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/images-temp/image8.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/images-temp/image9.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image1.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image10.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image11.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image2.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
android-client/data/testing-images/image3.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
android-client/data/testing-images/image4.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
android-client/data/testing-images/image5.jpg
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
android-client/data/testing-images/image6.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image7.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image8.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
android-client/data/testing-images/image9.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
2387
android-client/main.py
Normal file
BIN
android-client/modules/handler/__pycache__/info.cpython-310.pyc
Normal file
BIN
android-client/modules/handler/__pycache__/info.cpython-311.pyc
Normal file
42
android-client/modules/handler/info.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from PIL import Image
|
||||
import io
|
||||
from android.storage import app_storage_path
|
||||
root_path = app_storage_path()
|
||||
|
||||
class profile():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def username():
|
||||
pass
|
||||
|
||||
def name(self, first_name=None, last_name=None):
|
||||
if first_name:
|
||||
self.first_name
|
||||
if last_name:
|
||||
self.last_name
|
||||
|
||||
if first_name and last_name:
|
||||
pass
|
||||
|
||||
class image():
|
||||
def __init__(self, post_id):
|
||||
self.post_id = post_id
|
||||
self.path = None
|
||||
|
||||
def load(self, image_bytes):
|
||||
image_formats = ['png', 'jpg']
|
||||
for form in image_formats:
|
||||
try:
|
||||
self.path = root_path + f"data/images/{self.post_id}.{form}"
|
||||
with Image.open(io.BytesIO(image_bytes)) as recieved:
|
||||
recieved.save(self.path)
|
||||
print("saved image")
|
||||
break
|
||||
except:
|
||||
print("cant save image")
|
||||
self.path = None
|
||||
|
||||
def delete(self):
|
||||
os.remove(self.path)
|
||||
|
||||
108
android-client/modules/handler/request.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# MODULES
|
||||
from modules.session.session import wait
|
||||
|
||||
def dict_key_verify(dictionary, keys, mode="and", *args, **kwargs):
|
||||
if mode != "and" and mode != "or":
|
||||
mode = "and"
|
||||
if type(keys) != list:
|
||||
keys = [keys]
|
||||
|
||||
verified = []
|
||||
if type(keys) != list:
|
||||
keys = [keys]
|
||||
|
||||
for key in keys:
|
||||
if type(dictionary) != dict or key not in dictionary or not dictionary[key]:
|
||||
verified.append(False)
|
||||
else:
|
||||
verified.append(True)
|
||||
|
||||
if mode == "and":
|
||||
if all(verified) == True:
|
||||
return True
|
||||
if mode == "or":
|
||||
if True in verified:
|
||||
return True
|
||||
return False
|
||||
# MODULES
|
||||
class request():
|
||||
def __init__(self, sio, session=None, username=None):
|
||||
self.sio = sio
|
||||
self.session = session
|
||||
self.username = username
|
||||
|
||||
def callback(self, callback, data):
|
||||
self.session.transfer = data
|
||||
|
||||
def emit(self, event, info=None, callback_func="self.callback"):
|
||||
if callback_func == "self.callback":
|
||||
callback_func = self.callback
|
||||
if callback_func == None:
|
||||
self.sio.emit(event, info)
|
||||
return
|
||||
else:
|
||||
self.sio.emit(event, info, callback=callback_func)
|
||||
wait(self.session).wait()
|
||||
return self.session.transfer
|
||||
|
||||
class account_page(request):
|
||||
def refresh(self):
|
||||
info = self.get_profile()
|
||||
return info
|
||||
|
||||
def get_profile(self):
|
||||
info = {'username': self.username, 'name': self.username, 'role': "", 'occupation_name': "", 'team_name': "", 'biography': ""}
|
||||
|
||||
profile_data = {'username': self.username, 'items': ['name', 'role', 'biography']}
|
||||
profile_info = self.emit('profile_get', profile_data)
|
||||
|
||||
occupation_data = {'username': self.username, 'items': ['name']}
|
||||
occupation_info = self.emit('occupation_get', occupation_data)
|
||||
if dict_key_verify(occupation_info, 'name'):
|
||||
info['occupation_name'] = occupation_info['name']
|
||||
|
||||
team_data = {'username': self.username, 'items': ['name']}
|
||||
team_info = self.emit('team_get', team_data)
|
||||
if dict_key_verify(team_info, 'name'):
|
||||
info['team_name'] = team_info['name']
|
||||
|
||||
team_leader_info = self.emit('team_get_leaders')
|
||||
if dict_key_verify(team_leader_info, 'leaders'):
|
||||
if self.username in team_leader_info['leaders']:
|
||||
info['team_name'] += " (team lead)"
|
||||
|
||||
for key in profile_info.keys():
|
||||
if dict_key_verify(profile_info, key):
|
||||
info[key] = profile_info[key]
|
||||
|
||||
return info
|
||||
|
||||
def set_profile(self, item, new_value, username=None):
|
||||
profile = ['name', 'role', 'biography']
|
||||
occupation = ['occupation_name']
|
||||
team = ['team_name']
|
||||
|
||||
if item in profile:
|
||||
event = 'profile_set'
|
||||
|
||||
if item == 'name':
|
||||
new_values = new_value.split(" ")
|
||||
if len(new_values) == 2:
|
||||
items = ['first_name', 'last_name']
|
||||
if item in occupation:
|
||||
event = 'occupation_set'
|
||||
item = 'name'
|
||||
if item in team:
|
||||
event = 'team_set'
|
||||
item = 'name'
|
||||
|
||||
if type(item) != list:
|
||||
items = [item]
|
||||
if type(new_value) != list:
|
||||
new_values = [new_value]
|
||||
|
||||
for value, item in zip(new_values, items):
|
||||
data = {'username': None,'items': [item], item: value}
|
||||
if username:
|
||||
data['username'] = username
|
||||
self.emit('profile_set', data, None)
|
||||
BIN
android-client/modules/session/__pycache__/time.cpython-310.pyc
Normal file
BIN
android-client/modules/session/__pycache__/time.cpython-311.pyc
Normal file
143
android-client/modules/session/session.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import time
|
||||
import sqlite3
|
||||
from android.storage import app_storage_path
|
||||
root_path = app_storage_path()
|
||||
|
||||
class session_info():
|
||||
def __init__(self):
|
||||
self._logged_in = False
|
||||
self.username = None
|
||||
self.server_code = None
|
||||
self.cycle_count = 0
|
||||
self.auth_tokens = []
|
||||
self.transfer = None
|
||||
self.status = None
|
||||
|
||||
@property
|
||||
def logged_in(self):
|
||||
return self._logged_in
|
||||
@logged_in.setter
|
||||
def logged_in(self, value):
|
||||
self._logged_in = value
|
||||
self.cycle_count += 1
|
||||
|
||||
@property
|
||||
def transfer(self):
|
||||
return self._transfer
|
||||
@transfer.setter
|
||||
def transfer(self, value):
|
||||
self._transfer = value
|
||||
self.cycle_count += 1
|
||||
|
||||
def clear(self):
|
||||
db().execute("DELETE FROM tokens WHERE username = ?", (self.username,))
|
||||
self.__init__()
|
||||
|
||||
class wait():
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
self.last = self.session.cycle_count
|
||||
self.current = self.session.cycle_count
|
||||
|
||||
def current_update(self):
|
||||
self.current = self.session.cycle_count
|
||||
|
||||
def wait(self, status=None):
|
||||
while self.last == self.current:
|
||||
time.sleep(0.05)
|
||||
self.current_update()
|
||||
return
|
||||
|
||||
def wait_username(self):
|
||||
while not self.session.username:
|
||||
time.sleep(0.05)
|
||||
return
|
||||
|
||||
class db():
|
||||
def __init__(self):
|
||||
self.path = root_path + "/data/database.db"
|
||||
self._create()
|
||||
|
||||
def _create(self):
|
||||
con, cur = self._connect()
|
||||
|
||||
cur.execute("""CREATE TABLE IF NOT EXISTS tokens (
|
||||
token TEXT NOT NULL PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
expire TEXT NOT NULL
|
||||
)""")
|
||||
|
||||
cur.execute("""CREATE TABLE IF NOT EXISTS settings (
|
||||
title TEXT NOT NULL PRIMARY KEY,
|
||||
description TEXT,
|
||||
state BOOL,
|
||||
value TEXT,
|
||||
icon TEXT
|
||||
)""")
|
||||
|
||||
self._close(con)
|
||||
|
||||
def _connect(self):
|
||||
con = sqlite3.connect(self.path)
|
||||
cur = con.cursor()
|
||||
return con, cur
|
||||
|
||||
def execute(self, command, values=None):
|
||||
# we use this method so that closing and connecting to the datbase is abstracted away
|
||||
rez = None
|
||||
con, cur = self._connect()
|
||||
|
||||
if values:
|
||||
cur.execute(command, values)
|
||||
else:
|
||||
cur.execute(command)
|
||||
|
||||
if "SELECT" in command:
|
||||
rez = cur.fetchall()
|
||||
|
||||
self._close(con)
|
||||
if rez:
|
||||
return rez
|
||||
|
||||
def _commit(self, con):
|
||||
con.commit()
|
||||
|
||||
def _close(self, con):
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
class setting():
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
self.db = db()
|
||||
self.__fetch()
|
||||
|
||||
def __fetch(self):
|
||||
setting_data = self.db.execute("SELECT * FROM settings WHERE title = ?", (self.title,))
|
||||
if setting_data:
|
||||
self.title = setting_data[0][0]
|
||||
self.description = setting_data[0][1]
|
||||
if not self.description:
|
||||
self.description = ""
|
||||
|
||||
if setting_data[0][3] != None:
|
||||
self.value = setting_data[0][3]
|
||||
self.type = "text_field"
|
||||
else:
|
||||
self.value = setting_data[0][2]
|
||||
self.type = "swtich"
|
||||
|
||||
if setting_data[0][4] != None:
|
||||
self.icon = setting_data[0][4]
|
||||
else:
|
||||
self.icon = "cog"
|
||||
|
||||
def change_value(self, new_value):
|
||||
if self.type == "swtich" and isinstance(new_value, bool):
|
||||
self.db.execute("UPDATE settings SET state = ?", (new_value,))
|
||||
elif self.type == "text_field" and isinstance(new_value, str):
|
||||
self.db.execute("UPDATE settings SET value = ?", (new_value,))
|
||||
|
||||
63
android-client/modules/session/time.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from datetime import date, timedelta, datetime
|
||||
|
||||
class timestamp():
|
||||
@property
|
||||
def start(self):
|
||||
value = self.get_date_timestamp()
|
||||
self._start = value
|
||||
return self._start
|
||||
@start.setter
|
||||
def start(self, value):
|
||||
value = self.get_date_timestamp()
|
||||
self._start = value
|
||||
|
||||
@property
|
||||
def end(self):
|
||||
value = self.get_date_timestamp(day_mod=1) - 1
|
||||
self._end = value
|
||||
return self._end
|
||||
@end.setter
|
||||
def end(self, value):
|
||||
value = self.get_date_timestamp(day_mod=1) - 1
|
||||
self._end = value
|
||||
|
||||
@property
|
||||
def now(self):
|
||||
value = self.get_timestamp()
|
||||
self._now = value
|
||||
return value
|
||||
@now.setter
|
||||
def now(self, value):
|
||||
value = self.get_timestamp()
|
||||
self._now = value
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
date = str(datetime.now().date())
|
||||
self._date = date
|
||||
return self._date
|
||||
@date.setter
|
||||
def date(self, value):
|
||||
self._date = value
|
||||
|
||||
def get_date_timestamp(self, year_mod=0, month_mod=0, day_mod=0, *args, **kwargs):
|
||||
modifier = [year_mod, month_mod, day_mod]
|
||||
|
||||
now_mod = (datetime.now()+timedelta(days=day_mod))
|
||||
date = (str(now_mod.date()).replace("-0", "-")).split("-")
|
||||
date = [int(string) for string in date]
|
||||
|
||||
timestamp = datetime(date[0], date[1], date[2]).timestamp()
|
||||
|
||||
return timestamp
|
||||
|
||||
def get_timestamp(self):
|
||||
now = (float(datetime.now().timestamp()))
|
||||
return now
|
||||
|
||||
def get_date(self, timestamp):
|
||||
date = datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')
|
||||
return date
|
||||
|
||||
def get_days_month(self, month, year):
|
||||
pass
|
||||
3
android-client/modules/ui/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
android-client/modules/ui/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
android-client/modules/ui/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/ui.iml" filepath="$PROJECT_DIR$/.idea/ui.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
android-client/modules/ui/.idea/ui.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
1587
android-client/modules/ui/beopen.kv
Normal file
13
android-client/requirements.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cython
|
||||
python-socketio==5.8.0
|
||||
eventlet==0.33.3
|
||||
pathlib==1.0.1
|
||||
datetime
|
||||
pillow==9.5.0
|
||||
setuptools
|
||||
python-dotenv==1.0.0
|
||||
pyinstaller==6.3.0
|
||||
wheel==0.41.2
|
||||
packaging==23.2
|
||||
kivy[full]==2.3
|
||||
kivymd==1.1.1
|
||||
6
client/bugs.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
--- Load toolbar ---
|
||||
I fixed a teams help icon issue but made a major change unaware of consequences???
|
||||
I made it so the organisation bottom item now passes the "self.page" to the teams page and occupation page on creation instead of just "self"
|
||||
This is so these pages could have access to the load_toolbar method required to refresh the help button on previous pages
|
||||
--- Load toolbar ---
|
||||
|
||||
144
client/data/assets/help.txt
Normal file
@@ -0,0 +1,144 @@
|
||||
[Home:START]
|
||||
(title:START)
|
||||
Home page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
This is your home page, below you will is where you will see your friends posts.
|
||||
In the top left corner is your "profile" there you will be able to see all about you, and find friends
|
||||
Next to that is yout notifications to keep you up-to-date with your colleges
|
||||
Your settings panel is in the top left and additional areas are available in the navigation panel at the bottom of the page
|
||||
(body:END)
|
||||
[Home:END]
|
||||
|
||||
[Memories:START]
|
||||
(title:START)
|
||||
Memories page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here is where you will see your own historical posts. This means posts from previous days.
|
||||
Just select a month and then the day of the month and you will see your old post. You can still like
|
||||
and comment on it but others will not be able to see these interactions.
|
||||
(body:END)
|
||||
[Memories:END]
|
||||
|
||||
[Organisation:START]
|
||||
(title:START)
|
||||
Organisation page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you will see the navigation to your teams panel, and soon some infomation about your organisations
|
||||
Your teams panel is where you will be able to see all about your team.
|
||||
|
||||
You can only be part of one organisation, since your account is specifically tied to it.
|
||||
(body:END)
|
||||
[Organisation:END]
|
||||
|
||||
[Organisation-admin:START]
|
||||
(title:START)
|
||||
Organisation page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you will see the navigation to your teams panel, and soon some infomation about your organisations
|
||||
Your teams panel is where you will be able to see all about your team.
|
||||
Additionally since your are management/admin staff you can see the occupation area here you can accept and reject occupation change requests, create new occupations and edit or delete current ones.
|
||||
(body:END)
|
||||
[Organisation-admin:END]
|
||||
|
||||
[Profile:START]
|
||||
(title:START)
|
||||
Profile page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
This page you can see all the infomation about the profile your viewing. For your own profile you should see edit buttons next to some of infomation this means you can change or request to change this info.
|
||||
|
||||
Your role is simply how you describe your role in your team for instance "assistant"
|
||||
Your occupation determines what team you are put into, you can only be part of 1 team at a time.
|
||||
(body:END)
|
||||
[Profile:END]
|
||||
|
||||
[Notifications:START]
|
||||
(title:START)
|
||||
Notifications page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you will see notifications from your organisations admins and management, as well notifications about people interacting with your posts and when its time to make your post.
|
||||
(body:END)
|
||||
[Notifications:END]
|
||||
|
||||
[Settings:START]
|
||||
(title:START)
|
||||
Settings page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
This is where you can configure some options, for instance to stop seeing these help buttons toggle "Help Dialogs".
|
||||
(body:END)
|
||||
[Settings:END]
|
||||
|
||||
[Team:START]
|
||||
(title:START)
|
||||
Teams page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Your sorted into a team via your occupation, each occupation will have a team associated with it.
|
||||
People in the same team as you will see your posts and you will see theres. This means you will see posts from
|
||||
your team alongside posts from your friends.
|
||||
|
||||
Team leaders act as the moderator for the team. This means they can delete your posts and comments even if your
|
||||
commenting on your friends posts.
|
||||
(body:END)
|
||||
[Team:END]
|
||||
|
||||
[Occupation:START]
|
||||
(title:START)
|
||||
Occupations page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you can change edit and delete the occupations in your organisation, this panel is only available for management and admins.
|
||||
You can also approve and deny occupation change requests here. For a member to change their occupation they have to submit an occupation change request including what occupation they want to switch to. This request must be approved by management or above. Once approved the member is switched to their new team.
|
||||
(body:END)
|
||||
[Occupation:END]
|
||||
|
||||
[Friends:START]
|
||||
(title:START)
|
||||
Friends page
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
In BeOpen you dont follow people but friend people, this means both people accepted to be friends with eachother. Meaning you both see eachothers posts in your feed.
|
||||
On this page you will be able to see your current friends and remove them if wanted. On the requests page (button below) you can send new friend requests, and approve or deny current friend requests. On that page is also a list of recomended friends based on mutal friends.
|
||||
|
||||
To send a friend request to someone (who isnt in the recomended) type their username into the request box, their username has to match exactly.
|
||||
(body:END)
|
||||
[Friends:END]
|
||||
|
||||
[Camera:START]
|
||||
(title:START)
|
||||
Making a post
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
You will be able to make one of these posts once a day, you will see the countdown at the top this is how long you have to post. After this time has run out you will not be able to post for that day.
|
||||
To make a post just take a picture of whatever your doing right now and head onto the next screen.
|
||||
(body:END)
|
||||
[Camera:END]
|
||||
|
||||
[PostReview:START]
|
||||
(title:START)
|
||||
Making a post
|
||||
(title:END)
|
||||
|
||||
(body:START)
|
||||
Here you can review the image you just took and retake it if needed.
|
||||
You can also add a caption to your post, note that you cannot edit a post after its been created you can however delete it. So be sure this is what you want to post today since deleting means you will have to wait till tomorrow to post again.
|
||||
When your ready just hit post!
|
||||
(body:END)
|
||||
[PostReview:END]
|
||||
BIN
client/data/assets/profile.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
client/data/database.db
Normal file
BIN
client/data/images-temp/image1.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/images-temp/image10.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/images-temp/image11.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/images-temp/image2.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
client/data/images-temp/image3.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
client/data/images-temp/image4.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
client/data/images-temp/image5.jpg
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
client/data/images-temp/image6.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/images-temp/image7.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/images-temp/image8.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/images-temp/image9.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image1.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image10.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image11.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image2.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
client/data/testing-images/image3.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
client/data/testing-images/image4.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
client/data/testing-images/image5.jpg
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
client/data/testing-images/image6.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image7.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image8.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
client/data/testing-images/image9.jpg
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
2364
client/main.py
Normal file
BIN
client/modules/handler/__pycache__/info.cpython-310.pyc
Normal file
BIN
client/modules/handler/__pycache__/info.cpython-311.pyc
Normal file
BIN
client/modules/handler/__pycache__/request.cpython-310.pyc
Normal file
BIN
client/modules/handler/__pycache__/request.cpython-311.pyc
Normal file
BIN
client/modules/handler/__pycache__/requests.cpython-311.pyc
Normal file
38
client/modules/handler/info.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
class profile():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def username():
|
||||
pass
|
||||
|
||||
def name(self, first_name=None, last_name=None):
|
||||
if first_name:
|
||||
self.first_name
|
||||
if last_name:
|
||||
self.last_name
|
||||
|
||||
if first_name and last_name:
|
||||
pass
|
||||
|
||||
class image():
|
||||
def __init__(self, post_id):
|
||||
self.post_id = post_id
|
||||
self.path = None
|
||||
|
||||
def load(self, image_bytes):
|
||||
image_formats = ['png', 'jpg']
|
||||
for form in image_formats:
|
||||
try:
|
||||
self.path = f"data/images/{self.post_id}.{form}"
|
||||
with Image.open(io.BytesIO(image_bytes)) as recieved:
|
||||
recieved.save(self.path)
|
||||
break
|
||||
except:
|
||||
self.path = None
|
||||
|
||||
def delete(self):
|
||||
os.remove(self.path)
|
||||
|
||||
108
client/modules/handler/request.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# MODULES
|
||||
from modules.session.session import wait
|
||||
|
||||
def dict_key_verify(dictionary, keys, mode="and", *args, **kwargs):
|
||||
if mode != "and" and mode != "or":
|
||||
mode = "and"
|
||||
if type(keys) != list:
|
||||
keys = [keys]
|
||||
|
||||
verified = []
|
||||
if type(keys) != list:
|
||||
keys = [keys]
|
||||
|
||||
for key in keys:
|
||||
if type(dictionary) != dict or key not in dictionary or not dictionary[key]:
|
||||
verified.append(False)
|
||||
else:
|
||||
verified.append(True)
|
||||
|
||||
if mode == "and":
|
||||
if all(verified) == True:
|
||||
return True
|
||||
if mode == "or":
|
||||
if True in verified:
|
||||
return True
|
||||
return False
|
||||
# MODULES
|
||||
class request():
|
||||
def __init__(self, sio, session=None, username=None):
|
||||
self.sio = sio
|
||||
self.session = session
|
||||
self.username = username
|
||||
|
||||
def callback(self, callback, data):
|
||||
self.session.transfer = data
|
||||
|
||||
def emit(self, event, info=None, callback_func="self.callback"):
|
||||
if callback_func == "self.callback":
|
||||
callback_func = self.callback
|
||||
if callback_func == None:
|
||||
self.sio.emit(event, info)
|
||||
return
|
||||
else:
|
||||
self.sio.emit(event, info, callback=callback_func)
|
||||
wait(self.session).wait()
|
||||
return self.session.transfer
|
||||
|
||||
class account_page(request):
|
||||
def refresh(self):
|
||||
info = self.get_profile()
|
||||
return info
|
||||
|
||||
def get_profile(self):
|
||||
info = {'username': self.username, 'name': self.username, 'role': "", 'occupation_name': "", 'team_name': "", 'biography': ""}
|
||||
|
||||
profile_data = {'username': self.username, 'items': ['name', 'role', 'biography']}
|
||||
profile_info = self.emit('profile_get', profile_data)
|
||||
|
||||
occupation_data = {'username': self.username, 'items': ['name']}
|
||||
occupation_info = self.emit('occupation_get', occupation_data)
|
||||
if dict_key_verify(occupation_info, 'name'):
|
||||
info['occupation_name'] = occupation_info['name']
|
||||
|
||||
team_data = {'username': self.username, 'items': ['name']}
|
||||
team_info = self.emit('team_get', team_data)
|
||||
if dict_key_verify(team_info, 'name'):
|
||||
info['team_name'] = team_info['name']
|
||||
|
||||
team_leader_info = self.emit('team_get_leaders')
|
||||
if dict_key_verify(team_leader_info, 'leaders'):
|
||||
if self.username in team_leader_info['leaders']:
|
||||
info['team_name'] += " (team lead)"
|
||||
|
||||
for key in profile_info.keys():
|
||||
if dict_key_verify(profile_info, key):
|
||||
info[key] = profile_info[key]
|
||||
|
||||
return info
|
||||
|
||||
def set_profile(self, item, new_value, username=None):
|
||||
profile = ['name', 'role', 'biography']
|
||||
occupation = ['occupation_name']
|
||||
team = ['team_name']
|
||||
|
||||
if item in profile:
|
||||
event = 'profile_set'
|
||||
|
||||
if item == 'name':
|
||||
new_values = new_value.split(" ")
|
||||
if len(new_values) == 2:
|
||||
items = ['first_name', 'last_name']
|
||||
if item in occupation:
|
||||
event = 'occupation_set'
|
||||
item = 'name'
|
||||
if item in team:
|
||||
event = 'team_set'
|
||||
item = 'name'
|
||||
|
||||
if type(item) != list:
|
||||
items = [item]
|
||||
if type(new_value) != list:
|
||||
new_values = [new_value]
|
||||
|
||||
for value, item in zip(new_values, items):
|
||||
data = {'username': None,'items': [item], item: value}
|
||||
if username:
|
||||
data['username'] = username
|
||||
self.emit('profile_set', data, None)
|
||||
BIN
client/modules/session/__pycache__/session.cpython-310.pyc
Normal file
BIN
client/modules/session/__pycache__/session.cpython-311.pyc
Normal file
BIN
client/modules/session/__pycache__/time.cpython-310.pyc
Normal file
BIN
client/modules/session/__pycache__/time.cpython-311.pyc
Normal file
140
client/modules/session/session.py
Normal file
@@ -0,0 +1,140 @@
|
||||
import time
|
||||
import sqlite3
|
||||
|
||||
class session_info():
|
||||
def __init__(self):
|
||||
self._logged_in = False
|
||||
self.username = None
|
||||
self.server_code = None
|
||||
self.cycle_count = 0
|
||||
self.auth_tokens = []
|
||||
self.transfer = None
|
||||
self.status = None
|
||||
|
||||
@property
|
||||
def logged_in(self):
|
||||
return self._logged_in
|
||||
@logged_in.setter
|
||||
def logged_in(self, value):
|
||||
self._logged_in = value
|
||||
self.cycle_count += 1
|
||||
|
||||
@property
|
||||
def transfer(self):
|
||||
return self._transfer
|
||||
@transfer.setter
|
||||
def transfer(self, value):
|
||||
self._transfer = value
|
||||
self.cycle_count += 1
|
||||
|
||||
def clear(self):
|
||||
db().execute("DELETE FROM tokens")
|
||||
self.__init__()
|
||||
|
||||
class wait():
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
self.last = self.session.cycle_count
|
||||
self.current = self.session.cycle_count
|
||||
|
||||
def current_update(self):
|
||||
self.current = self.session.cycle_count
|
||||
|
||||
def wait(self, status=None):
|
||||
while self.last == self.current:
|
||||
time.sleep(0.05)
|
||||
self.current_update()
|
||||
return
|
||||
|
||||
def wait_username(self):
|
||||
while not self.session.username:
|
||||
time.sleep(0.05)
|
||||
return
|
||||
|
||||
class db():
|
||||
def __init__(self):
|
||||
self.path = "./data/database.db"
|
||||
self._create()
|
||||
|
||||
def _create(self):
|
||||
con, cur = self._connect()
|
||||
|
||||
cur.execute("""CREATE TABLE IF NOT EXISTS tokens (
|
||||
token TEXT NOT NULL PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
expire TEXT NOT NULL
|
||||
)""")
|
||||
|
||||
cur.execute("""CREATE TABLE IF NOT EXISTS settings (
|
||||
title TEXT NOT NULL PRIMARY KEY,
|
||||
description TEXT,
|
||||
state BOOL,
|
||||
value TEXT,
|
||||
icon TEXT
|
||||
)""")
|
||||
|
||||
self._close(con)
|
||||
|
||||
def _connect(self):
|
||||
con = sqlite3.connect(self.path)
|
||||
cur = con.cursor()
|
||||
return con, cur
|
||||
|
||||
def execute(self, command, values=None):
|
||||
rez = None
|
||||
con, cur = self._connect()
|
||||
|
||||
if values:
|
||||
cur.execute(command, values)
|
||||
else:
|
||||
cur.execute(command)
|
||||
|
||||
if "SELECT" in command:
|
||||
rez = cur.fetchall()
|
||||
|
||||
self._close(con)
|
||||
if rez:
|
||||
return rez
|
||||
|
||||
def _commit(self, con):
|
||||
con.commit()
|
||||
|
||||
def _close(self, con):
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
class setting():
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
self.db = db()
|
||||
self.__fetch()
|
||||
|
||||
def __fetch(self):
|
||||
setting_data = self.db.execute("SELECT * FROM settings WHERE title = ?", (self.title,))
|
||||
if setting_data:
|
||||
self.title = setting_data[0][0]
|
||||
self.description = setting_data[0][1]
|
||||
if not self.description:
|
||||
self.description = ""
|
||||
|
||||
if setting_data[0][3] != None:
|
||||
self.value = setting_data[0][3]
|
||||
self.type = "text_field"
|
||||
else:
|
||||
self.value = setting_data[0][2]
|
||||
self.type = "swtich"
|
||||
|
||||
if setting_data[0][4] != None:
|
||||
self.icon = setting_data[0][4]
|
||||
else:
|
||||
self.icon = "cog"
|
||||
|
||||
def change_value(self, new_value):
|
||||
if self.type == "swtich" and isinstance(new_value, bool):
|
||||
self.db.execute("UPDATE settings SET state = ?", (new_value,))
|
||||
elif self.type == "text_field" and isinstance(new_value, str):
|
||||
self.db.execute("UPDATE settings SET value = ?", (new_value,))
|
||||
|
||||
63
client/modules/session/time.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from datetime import date, timedelta, datetime
|
||||
|
||||
class timestamp():
|
||||
@property
|
||||
def start(self):
|
||||
value = self.get_date_timestamp()
|
||||
self._start = value
|
||||
return self._start
|
||||
@start.setter
|
||||
def start(self, value):
|
||||
value = self.get_date_timestamp()
|
||||
self._start = value
|
||||
|
||||
@property
|
||||
def end(self):
|
||||
value = self.get_date_timestamp(day_mod=1) - 1
|
||||
self._end = value
|
||||
return self._end
|
||||
@end.setter
|
||||
def end(self, value):
|
||||
value = self.get_date_timestamp(day_mod=1) - 1
|
||||
self._end = value
|
||||
|
||||
@property
|
||||
def now(self):
|
||||
value = self.get_timestamp()
|
||||
self._now = value
|
||||
return value
|
||||
@now.setter
|
||||
def now(self, value):
|
||||
value = self.get_timestamp()
|
||||
self._now = value
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
date = str(datetime.now().date())
|
||||
self._date = date
|
||||
return self._date
|
||||
@date.setter
|
||||
def date(self, value):
|
||||
self._date = value
|
||||
|
||||
def get_date_timestamp(self, year_mod=0, month_mod=0, day_mod=0, *args, **kwargs):
|
||||
modifier = [year_mod, month_mod, day_mod]
|
||||
|
||||
now_mod = (datetime.now()+timedelta(days=day_mod))
|
||||
date = (str(now_mod.date()).replace("-0", "-")).split("-")
|
||||
date = [int(string) for string in date]
|
||||
|
||||
timestamp = datetime(date[0], date[1], date[2]).timestamp()
|
||||
|
||||
return timestamp
|
||||
|
||||
def get_timestamp(self):
|
||||
now = (float(datetime.now().timestamp()))
|
||||
return now
|
||||
|
||||
def get_date(self, timestamp):
|
||||
date = datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')
|
||||
return date
|
||||
|
||||
def get_days_month(self, month, year):
|
||||
pass
|
||||
3
client/modules/ui/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
client/modules/ui/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
client/modules/ui/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/ui.iml" filepath="$PROJECT_DIR$/.idea/ui.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
client/modules/ui/.idea/ui.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
1591
client/modules/ui/beopen.kv
Normal file
13
client/requirements.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cython
|
||||
python-socketio==5.8.0
|
||||
eventlet==0.33.3
|
||||
pathlib==1.0.1
|
||||
datetime
|
||||
pillow==9.5.0
|
||||
setuptools
|
||||
python-dotenv==1.0.0
|
||||
pyinstaller==6.3.0
|
||||
wheel==0.41.2
|
||||
packaging==23.2
|
||||
kivy[full]==2.3
|
||||
kivymd==1.1.1
|
||||
132
depricated/server/recomend-old.py
Normal file
@@ -0,0 +1,132 @@
|
||||
from modules.user import info as user_info
|
||||
from modules.algorithms.univ import dict_key_verify
|
||||
from modules.algorithms.uuid import hash_string
|
||||
|
||||
class User():
|
||||
def __init__(self, username, origin=False):
|
||||
self.username = username
|
||||
self.friends = user_info.friend(username=username)
|
||||
self.origin = origin
|
||||
|
||||
self.exclude = []
|
||||
self.count = 1
|
||||
self.depth = 0
|
||||
self.score = 0
|
||||
|
||||
self.friend_list = []
|
||||
|
||||
def find_friends(self, exclude=[], **kwargs):
|
||||
self.exclude += exclude
|
||||
friends = self.friends.get()
|
||||
if dict_key_verify(friends, "friends"):
|
||||
self.__organise_friends(friends['friends'])
|
||||
|
||||
self.__find_excluded()
|
||||
|
||||
def __organise_friends(self, friends, **kwargs):
|
||||
for friend in friends:
|
||||
if friend['username'] not in self.exclude:
|
||||
self.friend_list.append(User(friend['username']))
|
||||
|
||||
def __find_excluded(self):
|
||||
if self.username not in self.exclude:
|
||||
self.exclude.append(self.username)
|
||||
if self.origin:
|
||||
self.exclude = self.exclude + [friend.username for friend in self.friend_list]
|
||||
requests = self.friends.get_requests()
|
||||
print(f"requests: {requests}")
|
||||
if dict_key_verify(requests, "requests"):
|
||||
self.exclude = self.exclude + [request for request in requests["requests"]]
|
||||
print(f"EXCLUDED: {self.exclude}")
|
||||
|
||||
def __hash__(self):
|
||||
obj_hash = hash_string(self.username)
|
||||
return obj_hash
|
||||
|
||||
class Graph():
|
||||
def __init__(self, username):
|
||||
self.origin_user = User(username, True)
|
||||
self.graph = [[]] * (10**7+7)
|
||||
|
||||
self.friend_directory = [None] * (10**7+7)
|
||||
self.friend_directory[hash(self.origin_user)] = self.origin_user
|
||||
self.exclude = []
|
||||
|
||||
def generate(self, depth=1):
|
||||
self.__add_user_friends(self.origin_user, self.origin_user, depth)
|
||||
|
||||
def __add_user_friends(self, origin, source, depth):
|
||||
origin.find_friends(self.exclude + [source.username])
|
||||
if hash(self.origin_user) == hash(origin):
|
||||
self.exclude += origin.exclude
|
||||
|
||||
for friend in origin.friend_list:
|
||||
friend_hash = hash(friend)
|
||||
self.__add_edge(hash(origin), friend_hash)
|
||||
if self.friend_directory[friend_hash]:
|
||||
self.friend_directory[friend_hash].count += 1
|
||||
self.friend_directory[friend_hash].depth += depth
|
||||
else:
|
||||
self.friend_directory[friend_hash] = friend
|
||||
|
||||
if depth-1 > 0:
|
||||
self.__add_user_friends(friend, origin, depth-1)
|
||||
|
||||
def __add_edge(self, node, edge):
|
||||
self.graph[node] = self.graph[node] + [edge]
|
||||
|
||||
|
||||
def dft(self):
|
||||
self.visted = []
|
||||
self.edge_stack = [hash(self.origin_user)]
|
||||
self.edge_queue = [hash(self.origin_user)]
|
||||
|
||||
self.__visit(self.edge_stack[0])
|
||||
|
||||
def __visit(self, origin):
|
||||
start_pos = self.graph[origin]
|
||||
self.__on_visit(origin)
|
||||
|
||||
self.edge_stack.pop(len(self.edge_stack)-1)
|
||||
self.visted.append(origin)
|
||||
|
||||
for neigbour in start_pos:
|
||||
if neigbour not in self.visted and neigbour not in self.edge_stack:
|
||||
self.edge_stack.append(neigbour)
|
||||
|
||||
while len(self.edge_stack) > 0:
|
||||
i = len(self.edge_stack) - 1
|
||||
self.__visit(self.edge_stack[i])
|
||||
|
||||
def __on_visit(self, origin):
|
||||
origin_obj = self.friend_directory[origin]
|
||||
origin_obj.score += origin_obj.depth
|
||||
|
||||
def recomend_friends(self):
|
||||
self.recomendations = []
|
||||
while len(self.recomendations) != len(self.visted):
|
||||
largest = User(username="")
|
||||
largest.score = -1
|
||||
for friend in self.visted:
|
||||
friend_obj = self.friend_directory[friend]
|
||||
if friend_obj not in self.recomendations and friend_obj.score > largest.score:
|
||||
largest = friend_obj
|
||||
self.recomendations.append(largest)
|
||||
|
||||
def recomend_friend(amount=1, depth=1):
|
||||
if depth not in [1, 2, 3, 4]:
|
||||
depth = 4
|
||||
friend_graph = Graph("user1")
|
||||
friend_graph.generate(depth)
|
||||
friend_graph.dft()
|
||||
friend_graph.recomend_friends()
|
||||
|
||||
recomended = [{'username': recomended.username} for recomended in friend_graph.recomendations[:amount]]
|
||||
print(recomended)
|
||||
return recomended
|
||||
|
||||
def main():
|
||||
recomend_friend(3, 4)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
156
depricated/server/recomendation.py
Normal file
@@ -0,0 +1,156 @@
|
||||
from modules.user import info as user_info
|
||||
from modules.algorithms.univ import dict_key_verify
|
||||
from modules.algorithms.uuid import hash_string
|
||||
|
||||
# RBP
|
||||
import time
|
||||
# RBP
|
||||
|
||||
class user():
|
||||
def __init__(self, username, origin=False, **kwargs):
|
||||
self.username = username
|
||||
self.origin = origin
|
||||
self.friend_list = []
|
||||
self.friends = user_info.friend(username=self.username)
|
||||
self.count = 1
|
||||
|
||||
def print_list(self):
|
||||
username_list = [friend.username for friend in self.friend_list]
|
||||
return username_list
|
||||
|
||||
def print_count(self):
|
||||
count_list = []
|
||||
for friend in self.friend_list:
|
||||
if self.friend_count[hash(friend)] != 0:
|
||||
count_list.append({friend.username: friend.count})
|
||||
return count_list
|
||||
|
||||
def get_friends(self, depth=1, exclude=[], **kwargs):
|
||||
friends = self.friends.get()
|
||||
if dict_key_verify(friends, "friends"):
|
||||
self.__organise_friends(friends['friends'], depth, exclude)
|
||||
|
||||
def __organise_friends(self, friends, depth=1, exclude=[], **kwargs):
|
||||
for friend in friends:
|
||||
if friend['username'] not in exclude:
|
||||
self.friend_list.append(user(friend['username']))
|
||||
|
||||
depth -= 1
|
||||
if depth > 0:
|
||||
if self.username not in exclude:
|
||||
exclude.append(self.username)
|
||||
if self.origin:
|
||||
exclude = exclude + [friend.username for friend in self.friend_list]
|
||||
|
||||
for friend in self.friend_list:
|
||||
friend.get_friends(depth=depth, exclude=exclude)
|
||||
|
||||
def count_friend_frequency_old(self):
|
||||
friend_count = []
|
||||
self.friend_count = self.__inspect_friends(friend_count)
|
||||
|
||||
def __inspect_friends_old(self, friend_count):
|
||||
for friend in self.friend_list:
|
||||
if friend.friend_list:
|
||||
friend_count = friend.__inspect_friends(friend_count)
|
||||
hash_friend_count = [hash(friend) for friend in friend_count]
|
||||
|
||||
found = False
|
||||
for i, friend_hash in enumerate(hash_friend_count):
|
||||
if friend_hash == hash(friend):
|
||||
friend_count[i].count += 1
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
friend_count.append(friend)
|
||||
|
||||
return friend_count
|
||||
|
||||
def count_friend_frequency(self):
|
||||
pre = time.time()
|
||||
friend_count = [0]*(10**7+7)
|
||||
print(f"friend_count took to create: {time.time() - pre}")
|
||||
self.friend_count = self.__inspect_friends(friend_count)
|
||||
|
||||
def __inspect_friends(self, friend_count):
|
||||
for friend in self.friend_list:
|
||||
if friend.friend_list:
|
||||
friend_count = friend.__inspect_friends(friend_count)
|
||||
print("returned")
|
||||
|
||||
print("")
|
||||
if friend in friend_count:
|
||||
pre = time.time()
|
||||
friend_count[hash(friend)].count += 1
|
||||
print(f"count lookup took: {time.time() - pre}")
|
||||
else:
|
||||
pre = time.time()
|
||||
friend_count[hash(friend)] = friend
|
||||
print(f"append lookup took: {time.time() - pre}")
|
||||
|
||||
print("RETURNING")
|
||||
return friend_count
|
||||
|
||||
def count_user_frequency(self):
|
||||
user_id = user_info.user_id(username=self.username).get()['user_id']
|
||||
self.cur.execute("SELECT COUNT * FROM friends WHERE friend_id = ?", (user_id,))
|
||||
rez = self.cur.fetchone()
|
||||
if rez:
|
||||
return rez[0]
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __hash__(self):
|
||||
obj_hash = hash_string(self.username)
|
||||
return obj_hash
|
||||
|
||||
def choose_recomendations(amount, origin_user):
|
||||
recomended = []
|
||||
recomended_hash = []
|
||||
for i in range(amount):
|
||||
largest = user("user")
|
||||
largest.count = 0
|
||||
|
||||
for friend in origin_user.friend_list:
|
||||
if origin_user.friend_count[hash(friend)] != 0:
|
||||
if hash(friend) not in recomended_hash:
|
||||
if friend.count > largest.count:
|
||||
largest = friend
|
||||
|
||||
elif friend.count == largest.count:
|
||||
largest_frequency = largest.count_user_frequency()
|
||||
friend_frequency = friend.count_user_frequency()
|
||||
|
||||
if friend_frequency > largest_frequency:
|
||||
largest = friend
|
||||
|
||||
recomended.append(largest)
|
||||
recomended_hash.append(hash(largest))
|
||||
|
||||
# RBP
|
||||
for i, friend in enumerate(recomended):
|
||||
print(f"{i}: {friend.username}")
|
||||
# RBP
|
||||
|
||||
return recomended
|
||||
|
||||
def friend_recomend(username, amount=1, depth=1, **kwargs):
|
||||
origin_user = user(username, origin=True)
|
||||
origin_user.get_friends(depth)
|
||||
print(f"origin_user: {origin_user.username}: {origin_user.print_list()}")
|
||||
|
||||
if not origin_user.friend_list:
|
||||
# NOT FINSIHED
|
||||
pass
|
||||
db.cur.execute("SELECT COUNT * FROM friends")
|
||||
|
||||
origin_user.count_friend_frequency()
|
||||
print(origin_user.print_count())
|
||||
recomended = choose_recomendations(amount, origin_user)
|
||||
|
||||
def main():
|
||||
friend_recomend("user1", 1, 3)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
docs/write-up.pdf
Normal file
1
flatpak/.flatpak-builder/ccache/disabled/ccache.conf
Normal file
@@ -0,0 +1 @@
|
||||
disable = true
|
||||