diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0a81fcd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Use an official GCC image +FROM gcc:latest + +# Set working directory +WORKDIR /app + +# Copy source files into the container +COPY . . + +# Create users directory if not present +RUN mkdir -p users + +# Compile the project +RUN g++ -std=c++17 -o netflix main.cpp + +# Set the entrypoint to run the CLI +CMD ["./netflix"] diff --git a/Inventory.h b/Inventory.h new file mode 100644 index 0000000..980924c --- /dev/null +++ b/Inventory.h @@ -0,0 +1,60 @@ +#ifndef INVENTORY_H +#define INVENTORY_H + +#include "movie.h" +#include "tvshows.h" +#include +#include + +class Inventory { +private: + vector contents; + +public: + ~Inventory() { + for (auto c : contents) delete c; + } + + void addContent(Content* c) { + contents.push_back(c); + } + + void displayAll() const { + for (const auto& c : contents) + c->display(); + } + + void displayByGenre(const string& genre) const { + for (const auto& c : contents) + if (c->getGenre() == genre) + c->display(); + } + + Content* searchByTitle(const string& title) { + for (auto& c : contents) + if (c->getTitle() == title) + return c; + return nullptr; + } + + void saveToFile(const string& filename) { + ofstream file(filename); + for (const auto& c : contents) + file << c->serialize() << "\n"; + file.close(); + } + + void loadFromFile(const string& filename) { + ifstream file(filename); + string line; + while (getline(file, line)) { + if (line.find("Movie|") == 0) + contents.push_back(Movie::deserialize(line)); + else if (line.find("TVShow|") == 0) + contents.push_back(TVShow::deserialize(line)); + } + file.close(); + } +}; + +#endif diff --git a/UserUtils.h b/UserUtils.h new file mode 100644 index 0000000..08da15d --- /dev/null +++ b/UserUtils.h @@ -0,0 +1,27 @@ +#ifndef USER_UTILS_H +#define USER_UTILS_H + +#include "user.h" +#include + +namespace fs = std::filesystem; + +inline bool userExists(const string& username) { + return fs::exists("users/" + username + ".txt"); +} + +inline User* loadUser(const string& username) { + ifstream file("users/" + username + ".txt"); + string line; + getline(file, line); + file.close(); + return User::deserialize(line); +} + +inline void saveUser(User* user) { + ofstream file("users/" + user->getUsername() + ".txt"); + file << user->serialize(); + file.close(); +} + +#endif diff --git a/content.h b/content.h new file mode 100644 index 0000000..5c10ad2 --- /dev/null +++ b/content.h @@ -0,0 +1,36 @@ + +#ifndef CONTENT_H +#define CONTENT_H + +#include +using namespace std; + +class Content { +protected: + string title; + string genre; + float rating; + bool is_rented; + bool is_purchased; + +public: + Content(string t, string g, float r) : title(t), genre(g), rating(r), is_rented(false), is_purchased(false) {} + + virtual void display() const = 0; + virtual float getRentCost() const = 0; + virtual float getPurchaseCost() const = 0; + + string getTitle() const { return title; } + string getGenre() const { return genre; } + float getRating() const { return rating; } + bool getIsRented() const { return is_rented; } + bool getIsPurchased() const { return is_purchased; } + + void setRented(bool val) { is_rented = val; } + void setPurchased(bool val) { is_purchased = val; } + + virtual string serialize() const = 0; + virtual ~Content() {} +}; + +#endif diff --git a/inventory.txt b/inventory.txt new file mode 100644 index 0000000..7ad1809 --- /dev/null +++ b/inventory.txt @@ -0,0 +1,41 @@ +Movie|The Matrix|Sci-Fi|8.7|0|0|136|4.99|14.99 +Movie|Inception|Sci-Fi|8.8|0|0|148|5.99|15.99 +Movie|Interstellar|Adventure|8.6|0|0|169|6.49|16.99 +Movie|The Dark Knight|Action|9.0|0|0|152|5.49|14.49 +Movie|Pulp Fiction|Crime|8.9|0|0|154|4.49|13.99 +Movie|The Godfather|Crime|9.2|0|0|175|5.99|15.49 +Movie|The Shawshank Redemption|Drama|9.3|0|0|142|5.99|14.99 +Movie|Forrest Gump|Drama|8.8|0|0|144|4.99|13.49 +Movie|Avengers: Endgame|Action|8.4|0|0|181|6.99|17.99 +Movie|Parasite|Thriller|8.6|0|0|132|5.49|14.49 +Movie|La La Land|Romance|8.0|0|0|128|3.99|11.99 +Movie|Spirited Away|Animation|8.6|0|0|125|4.49|12.49 +Movie|The Lion King|Animation|8.5|0|0|88|3.99|9.99 +Movie|Joker|Drama|8.4|0|0|122|5.99|13.99 +Movie|Tenet|Sci-Fi|7.5|0|0|150|4.99|12.99 +Movie|Gladiator|Action|8.5|0|0|155|5.49|13.99 +Movie|Django Unchained|Western|8.4|0|0|165|4.99|13.49 +Movie|Titanic|Romance|7.8|0|0|195|4.49|12.49 +Movie|The Social Network|Drama|7.7|0|0|120|3.99|10.99 +Movie|1917|War|8.3|0|0|119|4.99|13.99 + +TVShow|Stranger Things|Horror|8.9|0|0|4|8|3.99|12.99 +TVShow|Breaking Bad|Crime|9.5|0|0|5|13|4.99|14.99 +TVShow|Friends|Comedy|8.9|0|0|10|24|3.49|9.99 +TVShow|Game of Thrones|Fantasy|9.3|0|0|8|10|5.99|18.99 +TVShow|The Office|Comedy|8.8|0|0|9|22|3.49|9.99 +TVShow|Money Heist|Thriller|8.2|0|0|5|10|4.99|13.99 +TVShow|The Mandalorian|Sci-Fi|8.7|0|0|3|8|4.99|12.99 +TVShow|Sherlock|Mystery|9.1|0|0|4|3|3.99|11.99 +TVShow|Dark|Sci-Fi|8.8|0|0|3|8|4.99|12.49 +TVShow|Narcos|Crime|8.8|0|0|3|10|4.49|11.99 +TVShow|Brooklyn Nine-Nine|Comedy|8.4|0|0|8|20|3.49|9.49 +TVShow|Black Mirror|Sci-Fi|8.8|0|0|5|6|4.99|11.99 +TVShow|The Boys|Superhero|8.7|0|0|3|8|4.49|12.49 +TVShow|Peaky Blinders|Drama|8.8|0|0|6|6|4.49|13.99 +TVShow|The Witcher|Fantasy|8.1|0|0|2|8|4.99|13.49 +TVShow|Lucifer|Fantasy|8.2|0|0|6|10|3.99|10.99 +TVShow|How I Met Your Mother|Comedy|8.3|0|0|9|22|3.49|9.99 +TVShow|Rick and Morty|Animation|9.2|0|0|5|10|3.99|11.99 +TVShow|House of the Dragon|Fantasy|8.5|0|0|1|10|5.99|14.99 +TVShow|Squid Game|Thriller|8.0|0|0|1|9|4.49|12.49 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..dbbac56 --- /dev/null +++ b/main.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include "Inventory.h" +#include "user.h" +#include "UserUtils.h" + +using namespace std; +namespace fs = std::filesystem; + +const string ADMIN_USERNAME = "admin"; +const string ADMIN_PASSWORD = "admin123"; // For demo + +void userMenu(User* user, Inventory& inventory) { + int choice; + while (true) { + cout << "\nUSER MENU - " << user->getUsername() << "\n"; + cout << "1. Browse all content\n2. Search by title\n3. Rent\n4. Purchase\n5. Return\n6. View rented\n7. View purchased\n8. Charges due\n9. Logout\nChoice: "; + cin >> choice; + cin.ignore(); + + if (choice == 1) { + inventory.displayAll(); + } else if (choice == 2) { + string title; + cout << "Enter title: "; + getline(cin, title); + Content* c = inventory.searchByTitle(title); + if (c) c->display(); + else cout << "Not found.\n"; + } else if (choice == 3) { + string title; + cout << "Enter title to rent: "; + getline(cin, title); + Content* c = inventory.searchByTitle(title); + if (c) user->rent(c); + else cout << "Not found.\n"; + } else if (choice == 4) { + string title; + cout << "Enter title to purchase: "; + getline(cin, title); + Content* c = inventory.searchByTitle(title); + if (c) user->purchase(c); + else cout << "Not found.\n"; + } else if (choice == 5) { + string title; + cout << "Enter title to return: "; + getline(cin, title); + Content* c = inventory.searchByTitle(title); + if (c) user->returnItem(c); + else cout << "Not found.\n"; + } else if (choice == 6) { + user->viewRented(); + } else if (choice == 7) { + user->viewPurchased(); + } else if (choice == 8) { + user->viewCharges(); + } else if (choice == 9) { + saveUser(user); + cout << "Logged out.\n"; + break; + } else { + cout << "Invalid choice.\n"; + } + } +} + +void adminMenu(Inventory& inventory) { + int choice; + while (true) { + cout << "\nADMIN MENU\n"; + cout << "1. Add Movie\n2. Add TV Show\n3. Remove Content\n4. View All Content\n5. Logout\nChoice: "; + cin >> choice; + cin.ignore(); + + if (choice == 1) { + string title, genre; + float rating, rent, purchase; + int duration; + cout << "Enter title, genre, rating, duration, rent cost, purchase cost:\n"; + getline(cin, title); getline(cin, genre); + cin >> rating >> duration >> rent >> purchase; cin.ignore(); + inventory.addContent(new Movie(title, genre, rating, duration, rent, purchase)); + cout << "Movie added.\n"; + } else if (choice == 2) { + string title, genre; + float rating, rent, purchase; + int seasons, eps; + cout << "Enter title, genre, rating, seasons, eps/season, rent/season, purchase/season:\n"; + getline(cin, title); getline(cin, genre); + cin >> rating >> seasons >> eps >> rent >> purchase; cin.ignore(); + inventory.addContent(new TVShow(title, genre, rating, seasons, eps, rent, purchase)); + cout << "TV Show added.\n"; + } else if (choice == 3) { + string title; + cout << "Enter title to remove: "; + getline(cin, title); + // Simplified: just mark as not available, or skip (you can implement actual removal later) + cout << "Feature not implemented.\n"; + } else if (choice == 4) { + inventory.displayAll(); + } else if (choice == 5) { + cout << "Admin logged out.\n"; + break; + } else { + cout << "Invalid choice.\n"; + } + } +} + +int main() { + fs::create_directory("users"); + + Inventory inventory; + inventory.loadFromFile("inventory.txt"); + + while (true) { + int option; + cout << "\n--- NETFLIX CLI SYSTEM ---\n"; + cout << "1. User Sign Up\n2. User Login\n3. Admin Login\n4. Exit\nChoice: "; + cin >> option; + cin.ignore(); + + if (option == 1) { + string uname; + cout << "Enter new username: "; + getline(cin, uname); + if (userExists(uname)) { + cout << "Username already exists.\n"; + } else { + User* u = new User(uname); + saveUser(u); + cout << "Sign-up successful. You can now log in.\n"; + } + } else if (option == 2) { + string uname; + cout << "Enter username: "; + getline(cin, uname); + if (!userExists(uname)) { + cout << "User not found.\n"; + } else { + User* user = loadUser(uname); + cout << "Welcome " << user->getUsername() << "!\n"; + userMenu(user, inventory); + } + } else if (option == 3) { + string uname, pass; + cout << "Enter admin username: "; + getline(cin, uname); + cout << "Enter admin password: "; + getline(cin, pass); + if (uname == ADMIN_USERNAME && pass == ADMIN_PASSWORD) { + adminMenu(inventory); + } else { + cout << "Invalid admin credentials.\n"; + } + } else if (option == 4) { + inventory.saveToFile("inventory.txt"); + cout << "Exiting...\n"; + break; + } else { + cout << "Invalid input.\n"; + } + } + + return 0; +} diff --git a/movie.h b/movie.h new file mode 100644 index 0000000..545fcab --- /dev/null +++ b/movie.h @@ -0,0 +1,59 @@ +#ifndef MOVIE_H +#define MOVIE_H + +#include "content.h" +#include +#include + +class Movie : public Content { +private: + int duration; + float rent_cost; + float purchase_cost; + +public: + Movie(string t, string g, float r, int d, float rent, float purchase) + : Content(t, g, r), duration(d), rent_cost(rent), purchase_cost(purchase) {} + + void display() const override { + cout << "Movie: " << title << " | Genre: " << genre << " | Rating: " << rating + << " | Duration: " << duration << " mins | Rent: $" << rent_cost + << " | Purchase: $" << purchase_cost << endl; + } + + float getRentCost() const override { return rent_cost; } + float getPurchaseCost() const override { return purchase_cost; } + + string serialize() const override { + stringstream ss; + ss << "Movie|" << title << "|" << genre << "|" << rating << "|" << duration + << "|" << rent_cost << "|" << purchase_cost << "|" << is_rented << "|" << is_purchased; + return ss.str(); + } + + static Movie* deserialize(const string& line) { + stringstream ss(line); + string type, t, g; + float r; + int d; + float rent, purchase; + bool rented, purchased; + + getline(ss, type, '|'); + getline(ss, t, '|'); + getline(ss, g, '|'); + ss >> r; ss.ignore(); + ss >> d; ss.ignore(); + ss >> rent; ss.ignore(); + ss >> purchase; ss.ignore(); + ss >> rented; ss.ignore(); + ss >> purchased; + + Movie* m = new Movie(t, g, r, d, rent, purchase); + m->setRented(rented); + m->setPurchased(purchased); + return m; + } +}; + +#endif diff --git a/otw (1).md b/otw (1).md new file mode 100644 index 0000000..48d8836 --- /dev/null +++ b/otw (1).md @@ -0,0 +1,99 @@ +#LEVEL 0 +What the level asked for: Logging in to the game via SSH +Logic used: *Used # ssh bandit0@bandit.labs.overthewire.org -p 2220 # with password "bandit0". + *read the "readme" file using command ## cat readme ##. + +#LEVEL 1 +What the level asked for: *Read a file named "-" which is also used in commands so can't be used directly as file name. +Logic used: *Used ## ssh bandit1@bandit.labs.overthewire.org -p 2220 ## with password "ZjLjTmM6FvvyRnrb2rfNWOZOTa6ip5If". + *Use # cat ./- # to bypass filename error. + ./ specifies the current directory and prevents - from being interpreted as a command. + +#LEVEL 2 +What the level asked for: Reading a file with spaces in its name. +Logic used: *Used # ssh bandit2@bandit.labs.overthewire.org -p 2220 # with password "263JGJPfgU6LtdEvgfWU1XP5yac29mFx". + *Included spaces in file name itself by using double quotes and making it as a string. # cat "spaces in this filename" #. + +#LEVEL 3 +What the level asked for: Finding a hidden file. +Logic used: *Used # ssh bandit3@bandit.labs.overthewire.org -p 2220 # with password "MNk8KNH3Usiio41PRUEoDFPqfxLPlSmx". + *Used # ls -a # which lists hidden files (starting with .), and # cat # reads the hidden file. + +#LEVEL 4 +What the level asked for: Identifying the only human-readable file. +Logic used: *Used # ssh bandit4@bandit.labs.overthewire.org -p 2220 # with password "2WmrDFRmJIq3IPxneAaMGhap0pFhF3NJ". + *Used the # file # command to check the file type for each file listed using # ls #. + *# file file_name # the showing ASCII TXT is the required file. +#LEVEL 5 +What the level asked for: Find a file with specific properties (1033 bytes, non-executable and human-readable). +Logic used: *Used # ssh bandit5@bandit.labs.overthewire.org -p 2220 # with password "4oQYVPkxZOOEOO5pTW81FB8j8lxXGUQw". + *# find . -size 1033c -type f ! -executable -readable # + * find command used to locate a file file in current directory of size 1033bytes(using -size 1033cc command), type of file (-type f command),non-executable(using ! -executable command) and + readable(using -readable command). + +#LEVEL 6 +What the level asked for: Locate a file owned by user bandit7 and group bandit6. +Logic used: *Used # ssh bandit6@bandit.labs.overthewire.org -p 2220 # with password "HWasnPhtq9AVKe0dmk45nxy20cvUa6EG". + *# find / -user bandit7 -group bandit6 2>/dev/null # + *Search the entire system (/) for files owned by bandit7 and group bandit6. 2>/dev/null hides errors. + +#LEVEL 7 +What the level asked for: Extract a password next to the word "millionth" stored in the file data.txt +Logic used: *Used # ssh bandit7@bandit.labs.overthewire.org -p 2220 # with password "morbNTDkSW6jIlUc0ymOdMaLnOlFVAaj". + *# grep 'millionth' data.txt # + *(grep) searches for the line containing the keyword "millionth" in file data.txt + +#LEVEL 8 +What the level asked for: Find the only unique line in a file of duplicates. +Logic used: *Used # ssh bandit8@bandit.labs.overthewire.org -p 2220 # with password "dfwvzFQi4mU0wfNbFOe9RoWskMLg7eEc". + *# sort data.txt | uniq -u # + *(sort) puts the lines in the file in order; (uniq -u) filters out duplicates, leaving only the unique line. + +#LEVEL 9 +What the level asked for: Extract a human-readable string from binary data which has multiple "=" preceeding it. +Logic used: *Used # ssh bandit9@bandit.labs.overthewire.org -p 2220 # with password "4CKMh1JI91bUIZZPXDqGanal4xvAg0JM". + *# strings data.txt | grep '==' # + *(strings) extracts human-readable text from binaries; (grep) finds lines with == in a file named data.txt + +#LEVEL 10 +What the level asked for: Decode base64 data. +Logic used: *Used # ssh bandit10@bandit.labs.overthewire.org -p 2220 # with password "FGUW5ilLVJrxX9kMYMmlN4MgbpfMiqey". + *# base64 -d data.txt # + *(base64 -d) decodes the Base64-encoded password which can then be printed by using (cat). + +#LEVEL 11 +What the level asked for: Recover the password stored in the file data.txt, where all lowercase (a-z) and uppercase (A-Z) letters have been rotated by 13 positions +Logic used: *Used # ssh bandit11@bandit.labs.overthewire.org -p 2220 # with password "dtR173fZKb0RRsDFSGsg2RWnpNVj3qRr". + *# tr 'A-Za-z' 'N-ZA-Mn-za-m' < data.txt # + *(tr) performs ROT13 substitution (shifts letters by 13 positions). + +#LEVEL 12 +What the level asked for: Decompress a nested hexdump. +Logic used: *Used # ssh bandit12@bandit.labs.overthewire.org -p 2220 # with password "7x16WNeHIi5YkIhWsfFIqoognUTyj9Q4". + *# mktemp -d (create a temporary directory) + cp data.txt (copy the file) + cd (move to tmp directory using (cd)) + mv data.txt data (rename the file simpler by (mv)) + xxd -r data (xxd -r reverses a hexdump in binary) # + *After this use (file) to check for ASCII TXT if not then use recursive decompression with tools like gzip/tar/bbzip2 to extract nested files. + (cat) is used to read the file that shows ASCII TXT on using (file) on it. + + +#LEVEL 13 +What the level asked for: Log in as bandit14 using an SSH private key. +Logic used: *Used # ssh bandit13@bandit.labs.overthewire.org -p 2220 # with password "FO5dwFsc0cbaIiH0h8J2eUks2vdTDwAn". + *WAS NOT ABLE TO DO THIS BECAUSE EVERYTHING WAS RESULTING IN PERMISSION DENIED. + +#LEVEL 14 +What the level asked for: Submit the current level's password to port 30000 on localhost. +Logic used: *Used # ssh bandit14@bandit.labs.overthewire.org -p 2220 # with password "MU4VWeTyJk8ROof1qqmcBPaLh7lDCPvS". + *# cat /etc/bandit_pass/bandit14 | nc localhost 30000 # + *nc (netcat) sends the password to port 30000 + +#LEVEL 15 +What the level asked for: Submit the password to port 30001 using SSL encryption. +Logic used: *Used # ssh bandit15@bandit.labs.overthewire.org -p 2220 # with password "8xCjnmgoKbGLhHFAZlGE5Tmu4M2tKJQo". + *# cat /etc/bandit_pass/bandit15 | openssl s_client -connect localhost:30001 -ign_eof # + *(openssl s_client) establishes an SSL connection. + (-ign_eof) keeps the connection open until the server responds. + diff --git a/tvshows.h b/tvshows.h new file mode 100644 index 0000000..3352af2 --- /dev/null +++ b/tvshows.h @@ -0,0 +1,64 @@ +#ifndef TVSHOW_H +#define TVSHOW_H + +#include "content.h" +#include +#include + +class TVShow : public Content { +private: + int seasons; + int episodes_per_season; + float rent_cost_per_season; + float purchase_cost_per_season; + +public: + TVShow(string t, string g, float r, int s, int eps, float rent, float purchase) + : Content(t, g, r), seasons(s), episodes_per_season(eps), + rent_cost_per_season(rent), purchase_cost_per_season(purchase) {} + + void display() const override { + cout << "TV Show: " << title << " | Genre: " << genre << " | Rating: " << rating + << " | Seasons: " << seasons << " | Episodes/Season: " << episodes_per_season + << " | Rent/Season: $" << rent_cost_per_season + << " | Purchase/Season: $" << purchase_cost_per_season << endl; + } + + float getRentCost() const override { return seasons * rent_cost_per_season; } + float getPurchaseCost() const override { return seasons * purchase_cost_per_season; } + + string serialize() const override { + stringstream ss; + ss << "TVShow|" << title << "|" << genre << "|" << rating << "|" << seasons + << "|" << episodes_per_season << "|" << rent_cost_per_season + << "|" << purchase_cost_per_season << "|" << is_rented << "|" << is_purchased; + return ss.str(); + } + + static TVShow* deserialize(const string& line) { + stringstream ss(line); + string type, t, g; + float r; + int s, eps; + float rent, purchase; + bool rented, purchased; + + getline(ss, type, '|'); + getline(ss, t, '|'); + getline(ss, g, '|'); + ss >> r; ss.ignore(); + ss >> s; ss.ignore(); + ss >> eps; ss.ignore(); + ss >> rent; ss.ignore(); + ss >> purchase; ss.ignore(); + ss >> rented; ss.ignore(); + ss >> purchased; + + TVShow* show = new TVShow(t, g, r, s, eps, rent, purchase); + show->setRented(rented); + show->setPurchased(purchased); + return show; + } +}; + +#endif diff --git a/user.h b/user.h new file mode 100644 index 0000000..1783104 --- /dev/null +++ b/user.h @@ -0,0 +1,136 @@ +#ifndef USER_H +#define USER_H + +#include "content.h" +#include +#include +#include +#include +#include +#include + +using namespace std; + +class User { +private: + string username; + vector rented_titles; + vector purchased_titles; + float charges_due; + +public: + // Constructor + User(const string& uname) : username(uname), charges_due(0.0f) {} + + // Getters + string getUsername() const { return username; } + float getChargesDue() const { return charges_due; } + + // Rent content + void rent(Content* item) { + if (item->getIsRented()) { + cout << "This item is already rented.\n"; + return; + } + item->setRented(true); + rented_titles.push_back(item->getTitle()); + charges_due += item->getRentCost(); + cout << "Rented successfully. $" << item->getRentCost() << " added to charges.\n"; + } + + // Purchase content + void purchase(Content* item) { + if (item->getIsPurchased()) { + cout << "This item is already purchased.\n"; + return; + } + item->setPurchased(true); + purchased_titles.push_back(item->getTitle()); + charges_due += item->getPurchaseCost(); + cout << "Purchased successfully. $" << item->getPurchaseCost() << " added to charges.\n"; + } + + // Return rented content + void returnItem(Content* item) { + if (!item->getIsRented()) { + cout << "This item was not rented.\n"; + return; + } + item->setRented(false); + auto it = find(rented_titles.begin(), rented_titles.end(), item->getTitle()); + if (it != rented_titles.end()) { + rented_titles.erase(it); + } + cout << "Returned successfully.\n"; + } + + // View currently rented titles + void viewRented() const { + cout << "Rented Items:\n"; + if (rented_titles.empty()) { + cout << "None\n"; + } else { + for (const auto& title : rented_titles) + cout << "- " << title << endl; + } + } + + // View purchased titles + void viewPurchased() const { + cout << "Purchased Items:\n"; + if (purchased_titles.empty()) { + cout << "None\n"; + } else { + for (const auto& title : purchased_titles) + cout << "- " << title << endl; + } + } + + // View due charges + void viewCharges() const { + cout << "Total Charges Due: $" << charges_due << endl; + } + + // Convert to string for file storage + string serialize() const { + stringstream ss; + ss << username << "|" << charges_due << "|"; + + for (const auto& r : rented_titles) + ss << r << ","; + ss << "|"; + + for (const auto& p : purchased_titles) + ss << p << ","; + return ss.str(); + } + + // Restore from file + static User* deserialize(const string& line) { + stringstream ss(line); + string uname, charge_str, rented_str, purchased_str; + + getline(ss, uname, '|'); + getline(ss, charge_str, '|'); + getline(ss, rented_str, '|'); + getline(ss, purchased_str, '|'); + + User* u = new User(uname); + u->charges_due = stof(charge_str); + + stringstream rented_stream(rented_str); + string title; + while (getline(rented_stream, title, ',')) { + if (!title.empty()) u->rented_titles.push_back(title); + } + + stringstream purchased_stream(purchased_str); + while (getline(purchased_stream, title, ',')) { + if (!title.empty()) u->purchased_titles.push_back(title); + } + + return u; + } +}; + +#endif diff --git a/vedant.txt b/vedant.txt new file mode 100644 index 0000000..4de2325 --- /dev/null +++ b/vedant.txt @@ -0,0 +1 @@ +vedant|148||Inception, \ No newline at end of file