Original Post
Hello, I have a problem making a function work correctly for my school project. At times, I feel the output I receive is very random, and most of the time it should not act like it does. I just don't see why it won't work, and now I have grown so frustrated, that I fear for my computer screen if I continue trying to solve this. So I would really like anyone here to help me see what the problem is. I attached all of the code, which has been developed using Codeblocks with GNU, but I'll try also posting the important things here.
I need every member of a vector object printed out in a text file like this in userlist.txt:
Now, this particular user is created in main.cpp,
the "database" vector is inside a class, Userbase::userbase in dbmani.h,
I don't think session.h is needed, but it also contains some errors, which I think is attributed to secLev.
Now, the ERROR is, that when I choose to register a new person, it will rewrite the database completely wrong, and it will look like this, if I register user "asdf",
To make it even worse, if I register a third account, it will replace the second user, asdf, when it should in fact make a third account. It will also bug out, when I check if the desired username is unique, when creating a new account, and not find if the name has already taken. For instance, my program created ID:1 user, as always. Then I copied ID:1 user manually and replaced "ID:1" with "ID:2" and "name:admin" with "name:admina", like this,
If I try to create another "admin", it will find out that the username is not unique, if I try to create an account with the name "admina", it will not find "admina" among the users, and therfore it will complete the registration. The new userlist.txt will then look like this,
I don't think the regAcc() will read/write correct when I use writedb(), and errors only happen when I register a new user. Maybe some kind of newline bugs the reading?
Preproc.h looks like this, if curious,
By the way, the "status:Functional" may not be true if you see it in a comment above a function. I would be very grateful, and give out many internets, if anyone could point out the possible faults, since I'm relatively brain dead at the moment, and I can't really understand it.
Regards,
Boooke
I need every member of a vector object printed out in a text file like this in userlist.txt:
ID:1
created:Sun May 13 16:04:31 2012
name:admin
password:Admin1
security level:2
status:active
Now, this particular user is created in main.cpp,
#include "preproc.h"
#include "dbmani.h"
#include "session.h"
int main()
{
system("mkdir messages");
ifstream inFile;
inFile.open("userlist.txt");
if(inFile.good())
{
// ADD DATE OF MODIFICATION
cout << "USERLIST FOUND, READING USERS.\n\n";
userstats tempBuffer;
int userCount = -1;
int overCount = 0;
string buffer;
while(getline(inFile, buffer))
{
if (0 == buffer.find("ID:"))
{
userCount++;
if (userCount > overCount)
{
userbase.users.push_back(tempBuffer);
overCount++;
}
buffer.erase(0, 3);
tempBuffer.ID = buffer;
}
else if (0 == buffer.find("created:"))
{
buffer.erase(0, 8);
tempBuffer.date = buffer;
}
else if (0 == buffer.find("name:"))
{
buffer.erase(0, 5);
tempBuffer.name = buffer;
}
else if (0 == buffer.find("password:"))
{
buffer.erase(0, 9);
tempBuffer.password = buffer;
}
else if (0 == buffer.find("status:"))
{
buffer.erase(0,7);
if (buffer == "active")
tempBuffer.active = true;
else if (buffer == "inactive")
tempBuffer.active = false;
}
}
if (userCount == 0)
{
userbase.users.push_back(tempBuffer);
}
inFile.close();
}
else
{
cout << "NO USERS FOUND, CREATING NEW LIST.\n";
inFile.close();
// Determine current date
time_t rawtime;
struct tm * timeinfo;
time (&rawtime );
timeinfo = localtime ( &rawtime );
string cdate = asctime(timeinfo);
userstats userBuffer = {"1", cdate, "admin", "Admin1", admin, 1};
userbase.users.push_back(userBuffer);
ofstream outFile("userlist.txt");
outFile << "created: " << cdate;
outFile << "mod_date: " << cdate << "\n\n";
outFile << "ID:" << userbase.users[0].ID << "\n";
outFile << "created:" << userbase.users[0].date;
outFile << "name:" << userbase.users[0].name << "\n";
outFile << "password:"<< userbase.users[0].password << "\n";
outFile << "security level:" << userbase.users[0].secLev << "\n";
outFile << "status:active\n\n";
outFile.close();
}
// CHECK DIR
char ch;
cout << "Choices are listed below\n";
cout << "1) login\t2) Register an Account\n"
<< "q) Quit.\n";
cout << "Select option: ";
bool breakFlag = false;
while (breakFlag == false && cin.get(ch))
{
cin.ignore();
// Could use getch to eliminate errors instead.
switch (ch)
{
case '1': int logID;
logID = userbase.login();
if (logID)
{
logID -= 1;
loggedin(logID);
}
cout << "\nChoices are listed below\n";
cout << "1) login\t2) Register an Account\n"
<< "q) Quit.\n";
cout << "Select option: ";
break;
case '2': userbase.regAcc();
cout << "\nChoices are listed below\n";
cout << "1) login\t2) Register an Account\n"
<< "q) Quit.\n";
cout << "Select option: ";
break;
case 'q': breakFlag = true;
cout << "\nEXITING PROGRAM\n";
break;
default : cout << "Wrong input.\n\n";
}
}
return 0;
}
the "database" vector is inside a class, Userbase::userbase in dbmani.h,
#ifndef DBMANI_H_INCLUDED
#define DBMANI_H_INCLUDED
enum securityLevel {user = 0, moderator, admin};
struct userstats
{
string ID;
string date;
string name;
string password; // Password minimum: One capital letter and number included
securityLevel secLev; // 0/normal user (Costumer, can only interact through messages)
// 1/moderator (Can delete level 0 users and see list of users)
// 2/admin (Same as moderator, but right to delete moderators aswell, defines root password) - INERASABLE
bool active;
};
class Userbase
{
private:
string rootPass;
public:
Userbase();
void setPas();
void regAcc();
int login();
void writedb();
// void resetdb(string uP);
vector<userstats> users;
};
Userbase::Userbase()
{
rootPass = "Admin1";
}
// Objective: Change rootpassword. Possibly connect admin/root passwords -
// But having constructor-problems.
//STATUS: Functional
void Userbase::setPas()
{
cout << "Enter current root password: ";
string pass;
getline(cin, pass);
if (pass == Userbase::rootPass)
{
cout << "Select new rootPass: ";
getline(cin, pass);
Userbase::rootPass = pass;
cout << "Password is now \"" << Userbase::rootPass << "\" until system exit.\n\n";
}
else
cout << "Password incorrect.";
}
// Objective: To add member to vector database and call writedb
// Status: Functional
enum RegFlags {
notUnique, tooShort, tooLong, inappropriate
};
void Userbase::regAcc()
{
cout << "\nCREATING NEW USER\n";
string username, password;
cout << "Enter desired username: ";
getline(cin, username);
cout << "Enter desired password: ";
getline(cin,password);
const unsigned int dbsize = Userbase::users.size();
// Do background check to make sure username isn't taken
vector<RegFlags> regFlags;
for (unsigned int i = 0; i < dbsize; i++)
{
if (username == Userbase::users.name)
regFlags.push_back(notUnique);
}
if (password.size() < 6)
regFlags.push_back(tooShort);
if (password.size() > 15)
regFlags.push_back(tooLong);
if (regFlags.size() > 0)
{
cout << "\tREGISTRATION ERRORS: \n";
for (unsigned int j = 0; j < regFlags.size(); j++)
{
switch (regFlags[j])
{
case notUnique : cout << "\t" << j + 1 << ". Your desired username, "
<< username << ", has already been taken\n";
continue;
case tooShort : cout << "\t" << j + 1 << ". Your password is not long enough (six to 15 characters)\n";
break;
case tooLong : cout << "\t" << j + 1 << ". Your password is too long (six to 15 characters\n";
break;
case inappropriate: cout << "\t" << j + 1 << ". Your password is inappropiate.\n";
break;
}
}
cout << "\nREGISTRATION FAILED\n";
}
else
{
// Conversion of string value to integer value
int i_regID = dbsize + 1;
string str_regID;
std::stringstream out;
out << i_regID;
str_regID = out.str();
cout << str_regID;
// Date of creation
time_t rawtime;
struct tm * timeinfo;
time (&rawtime );
timeinfo = localtime ( &rawtime );
string cdate = asctime(timeinfo);
userstats regBuffer = {str_regID, cdate, username, password, user,1};
Userbase::users.push_back(regBuffer);
Userbase::writedb();
cout << "\nREGISTRATION COMPLETE\n";
}
}
// Objective: Required login to view functions
// Status: Functional
int Userbase::login()
{
cout << "\nLOGGING IN\n";
string username, password;
cout << "\tEnter username: ";
getline(cin, username);
cout << "\tEnter password: ";
getline(cin, password);
int loggedIn = 0; // 0 equals not logged in.
const int dbsize = Userbase::users.size();
for (int i = 0; i < dbsize; i++)
{
if (username == Userbase::users.name)
{
if (password == Userbase::users.password && Userbase::users.active == 1)
{
loggedIn = i+1;
}
}
}
if (loggedIn > 0 )
{
cout << "\n\nLOGIN SUCCESFUL\n";
cout << "Logged in as " << Userbase::users[loggedIn-1].name << ".\n";
return loggedIn;
}
else
{
cout << "Username/password incorrect.\n";
return loggedIn;
}
}
// Objective: Write vector database to .txt database
// Status: Functional
void Userbase::writedb()
{
unsigned int dbsize = Userbase::users.size();
ifstream inFile("userlist.txt");
string cdate_orig;
getline(inFile, cdate_orig);
cdate_orig.erase(0,9);
inFile.close();
ofstream outFile("userlist.txt", std::ios::trunc);
time_t rawtime;
struct tm * timeinfo;
time (&rawtime );
timeinfo = localtime ( &rawtime );
string cdate = asctime(timeinfo);
outFile << "created: " << cdate_orig << "\n";
outFile << "mod_date: " << cdate << "\n\n";
for (unsigned int i = 0; i < dbsize; i++)
{
time (&rawtime );
timeinfo = localtime ( &rawtime );
string cdate = asctime(timeinfo);
outFile << "ID:" << Userbase::users.ID << "\n";
outFile << "created:" << Userbase::users.date;
outFile << "name:" << Userbase::users.name << "\n";
outFile << "password:"<< Userbase::users.password << "\n";
if (Userbase::users.secLev == user)
outFile << "security level:0" << "\n";
else if (Userbase::users.secLev == moderator)
outFile << "security level:1" << "\n";
else if (Userbase::users.secLev == admin)
outFile << "security level:2" << "\n";
if (Userbase::users.active == true)
{
outFile << "status:active\n\n";
}
else if (Userbase::users.active == false)
{
outFile << "status:inactive\n\n";
}
}
outFile.close();
}
Userbase userbase;
#endif // DBMANI_H_INCLUDED
I don't think session.h is needed, but it also contains some errors, which I think is attributed to secLev.
#ifndef SESSION_H_INCLUDED
#define SESSION_H_INCLUDED
void listUsers(int logID);
void loggedin(int logID)
{
char ch;
bool breakFlag = false;
if (userbase.users[logID].secLev == user)
{
cout << "Member choices are listed below\n";
cout << "1) Check messages\t2) Write a message"
<< "\n3) See users\nq) Log out.\n";
cout << "Choice: ";
}
else if (userbase.users[logID].secLev == moderator || userbase.users[logID].secLev == admin)
{
cout << "Member choices are listed below\n";
cout << "1) Check messages\t2) Write a message"
<< "\n3) See users\nq) Log out.\n";
cout << "Choice: ";
}
while (breakFlag == false && cin.get(ch))
{
cin.ignore();
// Could use getch to eliminate errors instead.
if (userbase.users[logID].secLev == user)
{
switch (ch)
{
case '1':
break;
case '2':
break;
case '3': listUsers(logID);
break;
case 'q': breakFlag = true;
break;
default : cout << "Wrong input.\n\n";
}
cout << "\n\nMember choices are listed below\n";
cout << "1) Check messages\t2) Write a message"
<< "\n3) See users\nq) Log out.\n";
cout << "Choice: ";
}
else if (userbase.users[logID].secLev == moderator || userbase.users[logID].secLev == admin)
{
switch (ch)
{
case '1':
break;
case '2':
break;
case '3': listUsers(logID);
break;
case 'q': breakFlag = true;
break;
default : cout << "Wrong input.\n\n";
}
cout << "\n\nMember choices are listed below\n";
cout << "1) Check messages\t2) Write a message"
<< "\n3) See users\nq) Log out.\n";
cout << "Choice: ";
}
cout << "Select option: ";
}
cout << "\n\nLOGGING OUT\n\n";
}
void listUsers(int logID)
{
if (userbase.users[logID].secLev == user)
{
cout << "NAME\t\tRIGHTS\n";
for (int i = 0; i < userbase.users.size(); i++)
{
cout << userbase.users.name << "\t\t";
if (userbase.users.secLev == user)
cout << "User\n";
else if(userbase.users.secLev == moderator)
cout << "Moderator\n";
else if(userbase.users.secLev == admin)
cout << "Admin\n";
}
}
else if (userbase.users[logID].secLev == moderator || userbase.users[logID].secLev == admin)
{
cout << "ID\tNAME\t\tRIGHTS\n";
for (int i = 0; i < userbase.users.size(); i++)
{
cout << userbase.users.ID << "\t";
cout << userbase.users.name << "\t\t";
if (userbase.users.secLev == user)
cout << "User\n";
else if(userbase.users.secLev == moderator)
cout << "Moderator\n";
else if(userbase.users.secLev == admin)
cout << "Admin\n";
}
}
}
#endif // SESSION_H_INCLUDED
Now, the ERROR is, that when I choose to register a new person, it will rewrite the database completely wrong, and it will look like this, if I register user "asdf",
ID:1
created:Sun May 13 16:10:26 2012name:admin
password:Admin1
status:active
ID:2
created:Sun May 13 16:16:29 2012
name:asdf
password:asdfasdf
security level:0
status:active
To make it even worse, if I register a third account, it will replace the second user, asdf, when it should in fact make a third account. It will also bug out, when I check if the desired username is unique, when creating a new account, and not find if the name has already taken. For instance, my program created ID:1 user, as always. Then I copied ID:1 user manually and replaced "ID:1" with "ID:2" and "name:admin" with "name:admina", like this,
created: Sun May 13 16:22:44 2012
mod_date: Sun May 13 16:22:44 2012
ID:1
created:Sun May 13 16:22:44 2012
name:admin
password:Admin1
security level:2
status:active
ID:2
created:Sun May 13 16:22:44 2012
name:admina
password:Admin1
security level:2
status:active
If I try to create another "admin", it will find out that the username is not unique, if I try to create an account with the name "admina", it will not find "admina" among the users, and therfore it will complete the registration. The new userlist.txt will then look like this,
created: Sun May 13 16:22:44 2012
mod_date: Sun May 13 16:27:35 2012
ID:1
created:Sun May 13 16:22:44 2012name:admin
password:Admin1
status:active
ID:2
created:Sun May 13 16:27:35 2012
name:admina
password:asdfasdf
security level:0
status:active
I don't think the regAcc() will read/write correct when I use writedb(), and errors only happen when I register a new user. Maybe some kind of newline bugs the reading?
Preproc.h looks like this, if curious,
#ifndef PREPROC_H_INCLUDED
#define PREPROC_H_INCLUDED
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <time.h>
#include <cstdlib>
#include <sstream>
using std::cout;
using std::cin;
using std::ifstream;
using std::ofstream;
using std::vector;
using std::string;
#endif // PREPROC_H_INCLUDED
By the way, the "status:Functional" may not be true if you see it in a comment above a function. I would be very grateful, and give out many internets, if anyone could point out the possible faults, since I'm relatively brain dead at the moment, and I can't really understand it.
Regards,
Boooke