Newer
Older
#!/.venv/bin/python
# ---- IMPORTS ---- #
import os # Import os module for cls and executing commands through python
import json # Import json so we can handle our data.json file
import pprint # Pretty print for debugging
import re # Not used atm
import unicodedata # Not used atm
from operator import itemgetter # Used for sorting our results after a specific option.
# Opens a file and reads it so it's contents can be used as data for the program
# Opens file with R (read) with UTF 8 encoding as file
with open(filename, 'r', encoding='utf-8') as file:
data = json.load(file) # Assigns the file contents to data as json
file.close() # Close the file
return data
def save(data):
with open('data.json', 'w', encoding='utf-8') as file:
json.dump(data, file, ensure_ascii=False, indent=4)
file.close()
# Reload data
load()
# Get project count
def get_project_count(data):
return len(data) # Returns the len of the data list which is equivalent to the amount of projects
# Get project by ID
def get_project(data, id):
# Loops over a range with the length of the amount of projects present and gets a project if it matches the passed ID.
for n in range(0, get_project_count(data)):
if data[n]['project_id'] == id: # If the current projects ID corresponds to the ID we're looking for then...
return data[n] # Return the project at that index
# Get all unique techniques from project
def get_techniques(data):
techniques = [] # A list which will store the techniques found
for project in data: # For every project in our data
for tech in project['techniques_used']: # For every technique in that project
if tech not in techniques: # If it's not in the previously techniques, it's unique.
techniques.append(tech) # Append it to the list.
techniques.sort() # Sort it so it'll look nice.

Oliwer Mattsson
committed
return techniques
# Gets all unique techniques from all projects. ( NOT USED? )
technique_list = get_techniques(data) # Get all the unique techniques so we know what techniques we can expect.
technique_stats = {} # Creates a dictionary which will contain the id as a key and the name as a value.
current_techniques = [] # A list which will contain the found techniques.
for technique in technique_list: # For each unique technique we found with get_techniques()...
for project in data: # For every project in data, as we need to look over them all for each technique.
if technique in project['techniques_used']: # If the technique we're currently looking for is in the used techniques of the project we're iterating over.
current_techniques.append({'id': project['project_id'], 'name': project['project_name']}) # Create a new dict INSIDE the list with the project ID and project name.
technique_stats.update({technique: current_techniques.copy()}) # Updates the dictionary with the list WITH a dict inside.
current_techniques.clear() # Clears the buffer so a new key value pair can be created.
return technique_stats # Return a dict with all techniques and the projects which uses them.
# Fetches and sorts projects matching criteria from the specified list.
def search(data, sort_by='start_date', sort_order='desc', techniques=None, search=None, search_fields=None):
# If search str belongs to search and if so, make search lower case.

Oliwer Mattsson
committed
if isinstance(search, str):
for project in data: # For each project in data
results.append(project) # Add all projects in data
results = sorted(results, key=itemgetter(sort_by)) # Sorts our results based on a specific variable by using a lambda function with itemgetter.

Oliwer Mattsson
committed
if sort_order == 'desc': # If the sort order is set to desc, then reverse the list.

Oliwer Mattsson
committed
results.reverse()
if techniques is not None: # If there are techniques which are going to be filtered by..
for technique in get_techniques(data): # For each unique technique..
for project in results: # And for each project we've found so far..
if all(n in project['techniques_used'] for n in techniques): # If all the techniques we're looking for are inside the projects technique_used field..
pass # Then do nothing..
results.pop(results.index(project)) # Otherwise remove it from our results.
if search is not None: # If the search field isn't set to None..
search_results = [] # Create a list for our search results..
for project in results: # For every project we've found so far..
if search_fields is not None and search_fields != "" and search != "" and search_fields != ['None']: # If the searchf ield is not set to None AND search_fields is not empty AND search_fields is not an empty list..
for field in search_fields: # For each field in search fields..
substring = project[field] # Save the current field in substring so we can do operations on it..
# Check types before calling lower()

Oliwer Mattsson
committed
if isinstance(substring, str):
substring = substring.lower() # Make case insensitive
if substring.find(search) != -1: # If found
search_results.append(project)
break
elif isinstance(substring, int):
if str(substring).find(search) != -1:
search_results.append(project)
break
elif isinstance(substring, list): # If it's a list..
for subsubstring in substring: # We'll need to make another substring so we can iterate over each index of the list instead of just for multiple lists.
if isinstance(subsubstring, str):

Oliwer Mattsson
committed
if subsubstring.lower().find(search) != -1:
search_results.append(project)
break

Oliwer Mattsson
committed
elif isinstance(subsubstring, int):
if str(subsubstring).find(search) != -1:
search_results.append(project)
break
elif search_fields == "": # And if the search_fields is empty..
results.clear() # Clear all results

Oliwer Mattsson
committed
else:
for substring in list(project.values()):

Oliwer Mattsson
committed
# Check type before calling lower()
if isinstance(substring, str):
if substring.lower().find(search) != -1:
search_results.append(project)
break

Oliwer Mattsson
committed
elif isinstance(substring, int):
if str(substring).find(search) != -1:
search_results.append(project)
break

Oliwer Mattsson
committed
elif isinstance(substring, list):

Oliwer Mattsson
committed
if isinstance(subsubstring, str):
if subsubstring.lower().find(search) != -1:
search_results.append(project)
break

Oliwer Mattsson
committed
elif isinstance(subsubstring, int):
if str(subsubstring).find(search) != -1:
search_results.append(project)
break

Oliwer Mattsson
committed
results = search_results # Make results into search_results as they should be the same
return results # Returns our results.
def cls():
os.system('cls' if os.name == 'nt' else 'clear')
pass
def new_project(data):
cls()
# ---- COLLECT INFO ----
project_title = input("Project title: ")

Oliwer Mattsson
committed
project_id = get_project_count(data) + 1
techniques = input("\nWhat techniques does your project use? Write them out in the following format: python, java, html, css\n\nTechniques: ").replace(" ", "").lower().split(",")
description = input("Provide a description of your project: ")
url = input("Provide a link to the source code/demo of your project: ")
img_url = input("Image source (ex: logo.jpg): ")
# ---- COLLECT INFO ----
# lexicographical order sort aka alphabetical
techniques.sort()

Oliwer Mattsson
committed

Oliwer Mattsson
committed
"project_name": project_title,
"project_id": project_id,
"used_techniques": techniques,
"long_description": description,
"img_url": img_url,
"url": url

Oliwer Mattsson
committed

Oliwer Mattsson
committed
print("\n\nProject preview:\n")
pprint.pp(new_project)
option = int(input("\n1: Create\n2: Cancel\n> "))
if option == 1:
data.append(new_project)
save(data)

Oliwer Mattsson
committed
def list_projects(data):
cls()
for project in data:
pprint.pp(project)
print("\n")
def edit_project(data, id):
while True:
if id > get_project_count(data) or id < 0:
print("Project ID doesn't exist.\n")
id = int(input("Project_ID to edit: "))
else:
cls()
project = get_project(data, id)

Oliwer Mattsson
committed
project.pop('project_id') # Project ID shouldn't be changed
print(f"Editing project: {project['title']}\n")
pprint.pp(project)
print("")
for field in enumerate(project):
print(f"{field[0]}: {field[1]}")

Oliwer Mattsson
committed

Oliwer Mattsson
committed
def delete_project(data):
pass
def menu(data):
menu_items = ["Add new project", "List projects", "Edit existing project", "Delete project", "Quit"]
menu_index = 0
while True:
cls()

Oliwer Mattsson
committed
titular = r"""
____ _ __ _ _
| _ \ ___ _ __ | |_ / _| ___ | | (_) ___
| |_) | / _ \ | '__| | __| | |_ / _ \ | | | | / _ \
| __/ | (_) | | | | |_ | _| | (_) | | | _ | | | (_) |
|_| \___/ |_| \__| |_| \___/ |_| (_) |_| \___/
"""
print(titular)
for i in menu_items:

Oliwer Mattsson
committed
print(f"{menu_items.index(i) + 1}: {i}")
try:
option = int(input(f"> "))
if option == 1:
new_project(data)
elif option == 2:
list_projects(data)
input()
elif option == 3:
list_projects(data)
edit_project(data, int(input("Project_ID to edit: ")))
elif option == 4:
delete_project(data, int(input("Project_ID to delete: ")))
elif option == 5:
cls()
break
except:
print("")

Oliwer Mattsson
committed
if __name__ == "__main__":
main()