Permissions¶
Examples/Permissions¶
#include <SevenBit/DI.hpp>
#include <iostream>
using namespace sb::di;
enum class Permission : int
{
NONE = 0,
READ = 1,
UPDATE = 2,
ALL = READ | UPDATE
};
struct IUserPermission
{
virtual Permission getPermissions(int userId) = 0;
virtual ~IUserPermission() = default;
};
struct UserPermission final : IUserPermission
{
// normally fetch from database
Permission getPermissions(int userId) override { return Permission::READ; }
};
struct AdminPermission final : IUserPermission
{
Permission getPermissions(int userId) override { return Permission::ALL; }
};
struct Data
{
std::string name;
std::string payload;
};
struct IDataService
{
virtual const Data &getData() = 0;
virtual const Data &updateData(Data &&data) = 0;
virtual ~IDataService() = default;
};
// normally service would interact with database
class DataService final : public IDataService
{
IUserPermission &_userPermission;
Data _data = {"test name", "It is a long established fact that a reader will be distracted"};
public:
explicit DataService(IUserPermission &userPermission) : _userPermission(userPermission) {}
const Data &getData() override
{
assertPermission(Permission::READ);
return _data;
}
const Data &updateData(Data &&data) override
{
assertPermission(Permission::UPDATE);
_data = std::move(data);
return _data;
}
private:
void assertPermission(const Permission permission)
{
auto userPermission = _userPermission.getPermissions(1);
if (int check = static_cast<int>(userPermission) & static_cast<int>(permission);
static_cast<Permission>(check) != permission)
{
throw std::runtime_error("Insufficient permissions");
}
}
};
class Application
{
IDataService *_dataService;
public:
explicit Application(IDataService *dataService) : _dataService(dataService) {}
void run(const int argc, char *argv[])
{
try
{
processCmd(argc, argv);
}
catch (std::exception &e)
{
std::cout << "Error: " << e.what();
}
}
private:
void processCmd(const int argc, char *argv[])
{
const std::string_view operation = argc > 1 ? argv[1] : "read";
if (operation == "read")
{
printData(_dataService->getData());
}
else if (operation == "update")
{
if (argc < 4)
{
throw std::invalid_argument("Books args not provided");
}
printData(_dataService->updateData({argv[2], argv[3]}));
}
else
{
throw std::invalid_argument("Command not recognized");
}
}
void printData(const Data &book)
{
std::cout << "Name: " << book.name << ", Payload: " << book.payload << std::endl;
}
};
int main(int argc, char *argv[])
{
ServiceCollection services;
services.addSingleton<IUserPermission, UserPermission>();
services.addSingleton<IDataService, DataService>();
services.addSingleton<Application>();
if (const auto appMode = std::getenv("APP_MODE"); appMode && appMode == std::string_view{"DEVELOPMENT"})
{
services.removeAll<IUserPermission>();
services.addSingleton<IUserPermission, AdminPermission>();
}
auto provider = services.buildServiceProvider();
auto &application = provider.getService<Application>();
application.run(argc, argv);
}