diff --git a/README.md b/README.md index 1d993588179b5355d2b3018e11ff78fdfaa272fb..5f3771efb04786f2814eac1d3faae4562264b734 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework "SessionID": 111, "SessionType": "FRIEND", "Members": [ - { "username": "..." }, - { "username": "..." }, + { "Username": "..." }, + { "Username": "..." }, ], "Profile": [ "CreatedTime": "yyyy-mm-dd", @@ -52,6 +52,7 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework { "username": "..." }, ], "Profile": [ + "SessionName": "...", "CreatedTime": "yyyy-mm-dd", ] } diff --git a/Server/Server.pro b/Server/Server.pro index 4e68dbaefe2d0e4c9ffa5081bd75d86941b43a59..607ed281734be46c9ddab3d8b64ab5b12f692d9c 100644 --- a/Server/Server.pro +++ b/Server/Server.pro @@ -16,7 +16,9 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ - abstractsession.cpp \ + Session/abstractsession.cpp \ + Session/offlinesession.cpp \ + Session/onlinesession.cpp \ main.cpp \ messagemodel.cpp \ servermainwindow.cpp \ @@ -25,7 +27,9 @@ SOURCES += \ usermodel.cpp HEADERS += \ - abstractsession.h \ + Session/abstractsession.h \ + Session/offlinesession.h \ + Session/onlinesession.h \ ltest.h \ messagemodel.h \ servermainwindow.h \ diff --git a/Server/abstractsession.cpp b/Server/Session/abstractsession.cpp similarity index 44% rename from Server/abstractsession.cpp rename to Server/Session/abstractsession.cpp index 8dd5c17de09d7fcd7d55e691884a00818483c2c2..7b61ccbd9dcc019c66e356e1e5c365403ba1279f 100644 --- a/Server/abstractsession.cpp +++ b/Server/Session/abstractsession.cpp @@ -4,9 +4,3 @@ AbstractSession::AbstractSession(QObject *parent) : QObject(parent) { } - -OfflineSession::OfflineSession(UserContainer Users, QObject * parent) : - QObject(parent) -{ - members = Users; -} diff --git a/Server/abstractsession.h b/Server/Session/abstractsession.h similarity index 58% rename from Server/abstractsession.h rename to Server/Session/abstractsession.h index 0624ffc67c1a9a12875ad58393b40db739a285df..6decd30fa45bf3c9e476bd12f0a8f5ba6ce8b62a 100644 --- a/Server/abstractsession.h +++ b/Server/Session/abstractsession.h @@ -1,15 +1,12 @@ #include +#include #include "usermodel.h" -#include "messagemodel.h" #ifndef ABSTRACTSESSION_H #define ABSTRACTSESSION_H -#include - -using UserTypeName = UserModel; -using MessageContainer = QList; -using UserContainer = QList; +using UserTypeName = QString; +using UserContainer = QList; class AbstractSession : virtual public QObject { @@ -32,12 +29,4 @@ signals: }; -class OfflineSession: virtual public QObject, virtual public AbstractSession -{ - Q_OBJECT - -public: - OfflineSession(UserContainer argUsers, QObject * parent = nullptr); -}; - #endif // ABSTRACTSESSION_H diff --git a/Server/Session/offlinesession.cpp b/Server/Session/offlinesession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be1cbcb07b87f12d8f476549e7a57c3cd0800255 --- /dev/null +++ b/Server/Session/offlinesession.cpp @@ -0,0 +1,15 @@ +#include "offlinesession.h" + +OfflineSession::OfflineSession(UserContainer Users, AbstractSession * parent) : QObject(parent) +{ + if (Users.size() < 2) throw "ValueError"; + members = Users; +} + +OfflineSession::OfflineSession(QList Users, AbstractSession * parent) : QObject(parent) +{ + if (Users.size() < 2) throw "ValueError"; + for (int i = 0; i != Users.size(); i++) { + members.append(Users.at(i)->getUsername()); + } +} diff --git a/Server/Session/offlinesession.h b/Server/Session/offlinesession.h new file mode 100644 index 0000000000000000000000000000000000000000..57f1074221b57884e106448bde873a70bed081de --- /dev/null +++ b/Server/Session/offlinesession.h @@ -0,0 +1,16 @@ +#ifndef OFFLINESESSION_H +#define OFFLINESESSION_H + +#include +#include "Session/abstractsession.h" + +class OfflineSession: public AbstractSession +{ + Q_OBJECT + +public: + OfflineSession(UserContainer Users, AbstractSession * parent = nullptr); + OfflineSession(QList Users, AbstractSession * parent = nullptr); +}; + +#endif // OFFLINESESSION_H diff --git a/Server/Session/onlinesession.cpp b/Server/Session/onlinesession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf13c00694dda88a5bfb794c45ff37cc36527441 --- /dev/null +++ b/Server/Session/onlinesession.cpp @@ -0,0 +1,42 @@ +#include "onlinesession.h" + +OnlineSession::OnlineSession(QJsonObject &json, AbstractSession * parent) : + QObject(parent) +{ + loadDataFromJson(json); +} + +void OnlineSession::loadDataFromJson(const QJsonObject &json) +{ + id = json["SessionID"].toInt(); + loadUsersFromJson(json); + Profile = json["Profile"].toObject(); + if ((getSessionType() == SessionType::GROUP && json["SessionType"] == "GROUP") + || (getSessionType() == SessionType::FRIEND && json["SessionType"] == "FRIEND") ) + { + if (getSessionType() == SessionType::GROUP) { + SessionName = Profile["SessionName"].toString(); + } + else { + SessionName = "foo"; + } + } + else throw "load error"; +} + +const QString& OnlineSession::getSessionName() const { + if (getSessionType() == SessionType::FRIEND) + throw "FriendSession does not have a session name"; + return SessionName; +} + +void OnlineSession::loadUsersFromJson(const QJsonObject& json) +{ + QJsonArray userlist = json["Members"].toArray(); + if (userlist.size() < 2) throw "Value Error"; + for (int i = 0; i < userlist.size(); i++) { + QString usrname = userlist.at(i).toObject()["Username"].toString(); + members.append(usrname); + } + +} diff --git a/Server/Session/onlinesession.h b/Server/Session/onlinesession.h new file mode 100644 index 0000000000000000000000000000000000000000..b4f9b7fdd58328f55f44060a7a3862b698b3db07 --- /dev/null +++ b/Server/Session/onlinesession.h @@ -0,0 +1,26 @@ +#ifndef ONLINESESSION_H +#define ONLINESESSION_H + +#include +#include "Session/abstractsession.h" + +class OnlineSession: public AbstractSession +{ + Q_OBJECT + +public: + OnlineSession(QJsonObject &json, AbstractSession * parent = nullptr); + + int getSessionID() const { return id; } + const QString& getSessionName() const; + const QJsonObject& getProfile() const { return Profile; } + +private: + int id; + QString SessionName; + QJsonObject Profile; + + void loadUsersFromJson(const QJsonObject& json); + void loadDataFromJson(const QJsonObject& json); +}; +#endif // ONLINESESSION_H diff --git a/Server/ltest.h b/Server/ltest.h index 80ba56cc9f4df809685e31c5c4d084126e5ea135..4ce89151c8fb8432a8b40cb6d02fb8f3696deb92 100644 --- a/Server/ltest.h +++ b/Server/ltest.h @@ -1,87 +1,3 @@ -#ifndef H_COLORWHEEL -#define H_COLORWHEEL - -/* forked from https://github.com/Totoditoto/colorwheel */ - -#include -#include - -#define CW_TRACE(hd, ...) \ - do \ - { \ - fprintf(stderr, "%s:%d/%s(): " hd, __FILE__, __LINE__, \ - __func__, ##__VA_ARGS__); \ - fflush(stderr); \ - } while (0) - -#define CW_CMD(color_code) "\033[1;" #color_code "m" - -/* Style */ -#define CW_BRIGHT CW_CMD(1) -#define CW_DIM CW_CMD(2) - -/* Foreground colors */ -#define CW_RESET CW_CMD(0) -#define CW_BLACK CW_CMD(30) -#define CW_RED CW_CMD(31) -#define CW_GREEN CW_CMD(32) -#define CW_YELLOW CW_CMD(33) -#define CW_BLUE CW_CMD(34) -#define CW_PURPLE CW_CMD(35) -#define CW_CYAN CW_CMD(36) -#define CW_WHITE CW_CMD(37) - -/* Special commands */ -#define CW_ITALIC CW_CMD(03) -#define CW_UNDERLINE CW_CMD(04) - -/* Background colors */ -#define CW_BG_BLACK CW_CMD(40) -#define CW_BG_RED CW_CMD(41) -#define CW_BG_GREEN CW_CMD(42) -#define CW_BG_YELLOW CW_CMD(43) -#define CW_BG_BLUE CW_CMD(44) -#define CW_BG_PURPLE CW_CMD(45) -#define CW_BG_CYAN CW_CMD(46) -#define CW_BG_WHITE CW_CMD(47) - -/* Predefined message styles */ - -// Normal colored text -#define CW_NORMAL(msg, ...) CW_RESET " " msg " " CW_RESET "\n" - -// White text over red background for extreme warning information -#define CW_ALARM(msg, ...) CW_BRIGHT CW_WHITE CW_BG_RED " " msg " " CW_RESET "\n" - -// Red text over normal background for critical fault information -#define CW_CRITICAL(msg, ...) CW_BRIGHT CW_RED " " msg " " CW_RESET "\n" - -// Yellow text over grey background for fault information -#define CW_FAULT(msg, ...) CW_BRIGHT CW_YELLOW CW_BG_BLACK " " msg " " CW_RESET "\n" - -// Green text over grey background for confirmation/success information -#define CW_VALID(msg, ...) CW_BRIGHT CW_GREEN CW_BG_BLACK " " msg " " CW_RESET "\n" - -// Blue text over normal background for noticeable information -#define CW_INFO(msg, ...) CW_BRIGHT CW_BLUE " " msg " " CW_RESET "\n" - -/* Predefined printf styled messages */ -#define CW_PRINT_NORMAL(msg, ...) printf(CW_NORMAL(msg), ##__VA_ARGS__); -#define CW_PRINT_ALARM(msg, ...) printf(CW_ALARM(msg), ##__VA_ARGS__); -#define CW_PRINT_CRITICAL(msg, ...) printf(CW_CRITICAL(msg), ##__VA_ARGS__); -#define CW_PRINT_FAULT(msg, ...) printf(CW_FAULT(msg), ##__VA_ARGS__); -#define CW_PRINT_VALID(msg, ...) printf(CW_VALID(msg), ##__VA_ARGS__); -#define CW_PRINT_INFO(msg, ...) printf(CW_INFO(msg), ##__VA_ARGS__); - -/* Predefined CW_ styled messages */ -#define CW_TRACE_NORMAL(msg, ...) CW_TRACE(CW_NORMAL(msg), ##__VA_ARGS__); -#define CW_TRACE_ALARM(msg, ...) CW_TRACE(CW_ALARM(msg), ##__VA_ARGS__); -#define CW_TRACE_CRITICAL(msg, ...) CW_TRACE(CW_CRITICAL(msg), ##__VA_ARGS__); -#define CW_TRACE_FAULT(msg, ...) CW_TRACE(CW_FAULT(msg), ##__VA_ARGS__); -#define CW_TRACE_VALID(msg, ...) CW_TRACE(CW_VALID(msg), ##__VA_ARGS__); -#define CW_TRACE_INFO(msg, ...) CW_TRACE(CW_INFO(msg), ##__VA_ARGS__); - -#endif #ifndef __LTest_H__ #define __LTest_H__ @@ -108,10 +24,11 @@ public: \ #define ENDSUITE(name) \ } caseEntity##name; +#define CurPos "(" << __FILE__ << ":" << __LINE__ << ")" #define ERRMSG(msg)\ - CW_TRACE_CRITICAL("Error: %s", msg); \ + std::cout << "#... Error " << CurPos << ": " << msg << "." << std::endl; \ running_result = -1; \ return; @@ -124,6 +41,8 @@ public: \ ERRMSG(e) \ } catch(const char * e) {\ ERRMSG(e) \ + } catch(int e) {\ + ERRMSG("ErrCode = " << e) \ } catch(...) {\ ERRMSG("Unknown Error") \ } @@ -131,19 +50,17 @@ public: \ #define CASE(name) void SUITE_##name() #define EXE(testname) \ - CW_TRACE_NORMAL("Running Case = " #testname "..."); \ + std::cout << "# Running: case=" << #testname << "... " << std::endl; \ running_result = 0; \ SUITE_##testname(); \ test_pass += running_result == 0; \ test_num++; \ - test_error += running_result == -1; \ - if (running_result == 0) \ - CW_TRACE_VALID("PASS"); + test_error += running_result == -1; #define assertTrue(cond) \ ENV(\ if (!(cond)) {\ - CW_TRACE_CRITICAL("Assertion Failed: suppose " #cond " == true, but got false instead."); \ + std::cout << "#... Assertion Failed" << CurPos << " : suppose " << #cond << " == true, but got false instead." << std::endl; \ running_result = 1; \ return; \ }) @@ -151,15 +68,16 @@ ENV(\ #define assertEqual(a, b) \ ENV(\ if ((a) != (b)) {\ - CW_TRACE_CRITICAL("Assertion Failed: " #a " != " #b); \ + std::cout << "#... Assertion Failed" << CurPos <<": " \ + << #a << " != " << #b << std::endl; \ running_result = 1;\ return;\ } \ ) #define testlog(msgStr, args...) \ - CW_TRACE_INFO("LOG" msgStr, args) - + std::cout << "#... LOG " << CurPos << " ";\ + printf(msgStr "\n", args) class LTestCase { public: @@ -168,21 +86,27 @@ public: virtual void ctor() {} virtual void dtor() {} - void operator() () { + void operator() (bool simplify_output = false) { test_num = test_pass = test_error = 0; - CW_TRACE_NORMAL("Suite: %s", suitename.c_str()); + std::cout << "\nSuite: " << suitename << std::endl; + if (!simplify_output) { + std::cout << "##################" << std::endl; + } ctor(); execute(); + if (!simplify_output) + std::cout << "##################" << std::endl; if (test_num == test_pass) { - CW_TRACE_INFO ("%d Tests Passes In Total.", test_num); - CW_TRACE_VALID("Test Completed!"); + std::cout << test_pass << " Tests Passed In Total" << std::endl; + std::cout << "Test Completed! " << std::endl; } else { - CW_TRACE_CRITICAL("Test Suite Failed, Passed = %d, Failed = %d, Err = %d", test_pass, test_num - test_error - test_pass, test_error); + std::cout << "Pass " << test_pass << ", Fail " << test_num - test_error - test_pass; + std::cout << ", Error " << test_error << std::endl; } } diff --git a/Server/messagemodel.cpp b/Server/messagemodel.cpp index fb497d2b1a57b1c32be8bf047d5edbf4cc0c59ab..886898422ab80b50bf4c4b62cb2dc2ffb97f6af5 100644 --- a/Server/messagemodel.cpp +++ b/Server/messagemodel.cpp @@ -1,6 +1,17 @@ #include "messagemodel.h" -MessageModel::MessageModel(QObject *parent) : QObject(parent) +MessageModel::MessageModel(OnlineUserModel& senderUser, OnlineSession& sessionDest, QObject *parent) : + QObject(parent), + sender(senderUser), session(sessionDest) { - + senderUsername = senderUser.getUsername(); + sessionID = session.getSessionID(); } + +int MessageModel::getSessionID() const { return sessionID; } +const QString& MessageModel::getSenderUsername() const { return senderUsername; } +const OnlineSession& MessageModel::getSession() const { return session; } +const OnlineUserModel& MessageModel::getSender() const { return sender; } +const QString& MessageModel::getMessageText() const { return text; } +const QJsonObject& MessageModel::getMessageProfile() const { return profile; } + diff --git a/Server/messagemodel.h b/Server/messagemodel.h index 213249f77e1c4ed46dcec7099d8339991c1a55a9..43ce89e91411bd02f2cbccb3fc2a5d05b0298454 100644 --- a/Server/messagemodel.h +++ b/Server/messagemodel.h @@ -2,15 +2,49 @@ #define MESSAGEMODEL_H #include +#include "Session/abstractsession.h" +#include "Session/onlinesession.h" +#include "usermodel.h" -class MessageModel : virtual public QObject +class MessageModel : public QObject { Q_OBJECT public: - explicit MessageModel(QObject *parent = nullptr); + explicit MessageModel(OnlineUserModel& senderUser, OnlineSession& sessionDest, QObject *parent = nullptr); + int getSessionID() const; + const OnlineSession & getSession() const; + const QString& getSenderUsername() const; + const OnlineUserModel& getSender() const; + virtual int getMessageID() const { throw "Offline Message do not have messageID"; } + + const QString& getMessageText() const; + const QJsonObject& getMessageProfile() const; + + enum class Type { Offline, Online }; + virtual Type getType() const { return Type::Offline; } + + QJsonObject generateJsonOutput() const; + signals: +protected: + QString senderUsername; + const OnlineUserModel& sender; + int sessionID; + const OnlineSession& session; + QString text; + QJsonObject profile; + +}; + +class OnlineMessage : virtual public MessageModel +{ + Q_OBJECT +public: + explicit OnlineMessage(QObject * parent = nullptr); + + }; diff --git a/Server/testcases.cpp b/Server/testcases.cpp index bed273bfc82487e8420ad8afd30de41928fb4cc2..cceebf04c24d0ea6181ece40022374a9d8e6a8be 100644 --- a/Server/testcases.cpp +++ b/Server/testcases.cpp @@ -1,8 +1,11 @@ #include #include +#include #include "ltest.h" -#include "abstractsession.h" +#include "Session/abstractsession.h" +#include "Session/offlinesession.h" +#include "Session/onlinesession.h" using namespace std; @@ -41,9 +44,29 @@ CASE(CreatingASessionOutOfListOfThreeUser) { assertEqual(session.getSessionType(), AbstractSession::SessionType::GROUP); } +CASE(CreatingLocalSessionWithJsonObject) { + QJsonObject json, user; + QJsonArray userlist; + json["MsgType"] = "SessionData"; + json["SessionID"] = 101; + json["SessionType"] = "FRIEND"; + + user["Username"] = "UserA"; + userlist.append(user); + user["Username"] = "UserB"; + userlist.append(user); + json["Members"] = userlist; + + OnlineSession session(json); + assertEqual(session.getSessionID(), 101); + assertEqual(session.getSessionType(), AbstractSession::SessionType::FRIEND); + assertEqual(session.getMemberCount(), 2); +} + void execute() { EXE(CreatingASessionOutOfListOfTwoUser); EXE(CreatingASessionOutOfListOfThreeUser); + EXE(CreatingLocalSessionWithJsonObject); } ENDSUITE(SessionTest) @@ -83,3 +106,23 @@ void execute() { } ENDSUITE(UserTest) + +TESTSUITE(MessageTest) + +CASE(NewMessageFromOnlineUserAndSession) +{ + OfflineUserModel userA("userA", &obj); + userA.setNickname("nicknameA"); + userA.setSigniture("None"); + auto json = userA.generateUserModelJson(); + OfflineUserModel userB("userB", &obj); + userB.setNickname("nicknameB"); + userB.setSigniture("None Either"); + json = userB.generateUserModelJson(); + +} + +void execute() { + EXE(NewMessageFromOnlineUserAndSession); +} +ENDSUITE(MessageTest) diff --git a/Server/usermodel.h b/Server/usermodel.h index 25542e7ac98564c0b2b8c4a65100910aafa8fb79..85fcabbc3eff22838972015e378cd687f57f1109 100644 --- a/Server/usermodel.h +++ b/Server/usermodel.h @@ -13,6 +13,7 @@ public: UserModel(QObject *parent = nullptr); enum class Type { Offline, Online, None}; virtual Type getType() const { return Type::None; } + const QString& getUsername() const { return username; } signals: @@ -45,7 +46,6 @@ class OnlineUserModel : virtual public UserModel, virtual public QObject public: OnlineUserModel(QJsonObject &json, QObject *parent = nullptr); Type getType() const { return Type::Online; } - const QString& getUsername() const { return username; } const QString& getNickname() const { return nickname; } const QString getSigniture() const { return profile["Signiture"].toString(); } @@ -54,4 +54,16 @@ signals: private: void loadBasicInfoFromJson(QJsonObject &json); }; + +class LocalUser : virtual public OnlineUserModel +{ + Q_OBJECT +public: + + +signals: + +private: +}; + #endif // USERMODEL_H