414 lines
9.8 KiB
C++
414 lines
9.8 KiB
C++
/*
|
|
* This file is a part of Winix
|
|
* and is distributed under the 2-Clause BSD licence.
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2008-2021, Tomasz Sowa
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#include "db.h"
|
|
#include "core/log.h"
|
|
#include "core/misc.h"
|
|
|
|
|
|
namespace Winix
|
|
{
|
|
|
|
//void Db::PostgreSQLsmallerThan10(bool is_smaller_than_10)
|
|
//{
|
|
// is_postgresql_smaller_than_10 = is_smaller_than_10;
|
|
//
|
|
// if( is_postgresql_smaller_than_10 )
|
|
// {
|
|
// postgrsql_row_statement.clear();
|
|
// }
|
|
// else
|
|
// {
|
|
// postgrsql_row_statement = L"ROW";
|
|
// }
|
|
//}
|
|
|
|
|
|
/*
|
|
bool Db::GetUserPass(const std::wstring & login, long & user_id, UserPass & up)
|
|
{
|
|
PGresult * r = 0;
|
|
bool user_ok = false;
|
|
user_id = -1;
|
|
|
|
try
|
|
{
|
|
query.Clear();
|
|
query << R("select id, has_pass, password, pass_encrypted, pass_type, pass_hash_salted from core.user where login=")
|
|
<< login
|
|
<< R(";");
|
|
|
|
r = AssertQuery(query);
|
|
AssertResult(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = Rows(r);
|
|
|
|
if( rows == 0 )
|
|
throw Error(WINIX_ERR_DB_INCORRECT_LOGIN);
|
|
|
|
if( rows > 1 )
|
|
{
|
|
log << log1 << "Db: there is more than one user: " << login << logend;
|
|
throw Error(WINIX_ERR_DB_MORE_THAN_ONE_LOGIN);
|
|
}
|
|
|
|
int cuser_id = AssertColumn(r, "id");
|
|
int chas_pass = AssertColumn(r, "has_pass");
|
|
int cpass_type = AssertColumn(r, "pass_type");
|
|
int csalted = AssertColumn(r, "pass_hash_salted");
|
|
int cpassword = AssertColumn(r, "password");
|
|
int cpass_encrypted = AssertColumn(r, "pass_encrypted");
|
|
|
|
user_ok = true;
|
|
user_id = AssertValueLong(r, 0, cuser_id);
|
|
up.has_pass = AssertValueBool(r, 0, chas_pass);
|
|
up.pass_type = AssertValueInt(r, 0, cpass_type);
|
|
up.pass_hash_salted = AssertValueBool(r, 0, csalted);
|
|
AssertValueWide(r, 0, cpassword, up.pass);
|
|
AssertValueBin(r, 0, cpass_encrypted, up.pass_encrypted);
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return user_ok;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Error Db::AddUser(User & user, const UserPass & up)
|
|
{
|
|
PGresult * r = 0;
|
|
Error status = WINIX_ERR_OK;
|
|
|
|
try
|
|
{
|
|
query.Clear();
|
|
query << R("insert into core.user (login, has_pass, password, pass_encrypted, super_user, email,"
|
|
"notify, pass_type, pass_hash_salted, env, aenv, status, locale_id, time_zone_id) values (")
|
|
<< user.name
|
|
<< up.has_pass;
|
|
|
|
// for safety we put up.pass only if there is not an encrypted version
|
|
// someone could have forgotten to clear up.pass
|
|
if( up.pass_encrypted.empty() )
|
|
query << up.pass;
|
|
else
|
|
query << "";
|
|
|
|
query.EPutBin(up.pass_encrypted);
|
|
|
|
query << user.super_user
|
|
<< user.email
|
|
<< user.notify
|
|
<< up.pass_type
|
|
<< up.pass_hash_salted
|
|
<< user.env
|
|
<< user.aenv
|
|
<< user.status
|
|
<< user.locale_id
|
|
<< user.time_zone_id
|
|
<< R(");");
|
|
|
|
r = AssertQuery(query);
|
|
AssertResult(r, PGRES_COMMAND_OK);
|
|
|
|
user.id = AssertCurrval("core.user_id_seq");
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
status = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
Error Db::ChangeUserPass(long user_id, const UserPass & up)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(has_pass, password, pass_encrypted,"
|
|
"pass_type, pass_hash_salted) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< up.has_pass;
|
|
|
|
// for safety
|
|
if( up.pass_encrypted.empty() )
|
|
query << up.pass;
|
|
else
|
|
query << "";
|
|
|
|
query.EPutBin(up.pass_encrypted);
|
|
|
|
query << up.pass_type
|
|
<< up.pass_hash_salted
|
|
<< R(") where id=")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserEnv(long user_id, const PT::Space & space)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(env) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< space
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserAdminEnv(long user_id, const PT::Space & space)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(aenv) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< space
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserStatus(long user_id, int status)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(status) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< status
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
|
|
Error Db::ChangeUserEmail(long user_id, const std::wstring & email)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(email) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< email
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserLocale(long user_id, size_t locale_id)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(locale_id) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< locale_id
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserTimeZone(long user_id, size_t time_zone_id)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(time_zone_id) = ") << R(postgrsql_row_statement) << R("(")
|
|
<< time_zone_id
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::RemoveUser(long user_id)
|
|
{
|
|
query.Clear();
|
|
query << R("delete from core.user where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
void Db::GetUsers(UGContainer<User> & user_tab)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
query.Clear();
|
|
query << R("select id, login, super_user, group_id, email, notify,"
|
|
" env, aenv, status, locale_id, time_zone_id"
|
|
" from core.user left outer join core.group_mem on"
|
|
" core.user.id = core.group_mem.user_id order by id asc;");
|
|
|
|
r = AssertQuery(query);
|
|
AssertResult(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = Rows(r);
|
|
|
|
int cid = AssertColumn(r, "id");
|
|
int cname = AssertColumn(r, "login");
|
|
int csuper_user = AssertColumn(r, "super_user");
|
|
int cgroup_id = AssertColumn(r, "group_id");
|
|
int cemail = AssertColumn(r, "email");
|
|
int cnotify = AssertColumn(r, "notify");
|
|
int cenv = AssertColumn(r, "env");
|
|
int caenv = AssertColumn(r, "aenv");
|
|
int cstatus = AssertColumn(r, "status");
|
|
int clocale_id = AssertColumn(r, "locale_id");
|
|
int ctzone_id = AssertColumn(r, "time_zone_id");
|
|
|
|
User u;
|
|
long last_id = -1;
|
|
UGContainer<User>::Iterator iter = user_tab.End();
|
|
|
|
for(int i=0 ; i<rows ; ++i)
|
|
{
|
|
u.id = AssertValueLong(r, i, cid);
|
|
|
|
if( u.id != last_id )
|
|
{
|
|
u.name = AssertValueWide(r, i, cname);
|
|
u.super_user = AssertValueBool(r, i, csuper_user);
|
|
u.email = AssertValueWide(r, i, cemail);
|
|
u.notify = AssertValueInt(r, i, cnotify);
|
|
u.status = AssertValueInt(r, i, cstatus);
|
|
u.locale_id = (size_t)AssertValueInt(r, i, clocale_id);
|
|
u.time_zone_id = (size_t)AssertValueInt(r, i, ctzone_id);
|
|
AssertValueSpace(r, i, cenv, u.env);
|
|
AssertValueSpace(r, i, caenv, u.aenv);
|
|
|
|
log << log2 << "Db: user: id: " << u.id << ", name: " << u.name << ", super_user: " << u.super_user << logend;
|
|
|
|
iter = user_tab.PushBack(u);
|
|
|
|
if( iter == user_tab.End() )
|
|
log << log1 << "Db: can't add a user: " << u.name << logend;
|
|
|
|
last_id = u.id;
|
|
}
|
|
|
|
long group_id = AssertValueLong(r, i, cgroup_id);
|
|
|
|
if( !IsNull(r, i, cgroup_id) && group_id!=-1 && iter!=user_tab.End() )
|
|
{
|
|
iter->groups.push_back(group_id);
|
|
log << log3 << "Db: user:" << iter->name << " is a member of group_id: " << group_id << logend;
|
|
}
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
void Db::GetGroups(UGContainer<Group> & group_tab)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
query.Clear();
|
|
query << R("select id, core.group.group, user_id from core.group left outer join"
|
|
" core.group_mem on core.group.id = core.group_mem.group_id order by id asc;");
|
|
|
|
r = AssertQuery(query);
|
|
AssertResult(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = Rows(r);
|
|
|
|
int cid = AssertColumn(r, "id");
|
|
int cname = AssertColumn(r, "group");
|
|
int cuser_id = AssertColumn(r, "user_id");
|
|
|
|
Group g;
|
|
long last_id = -1;
|
|
UGContainer<Group>::Iterator iter;
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
g.id = AssertValueLong(r, i, cid);
|
|
|
|
if( g.id != last_id )
|
|
{
|
|
g.name = AssertValueWide(r, i, cname);
|
|
log << log3 << "Db: get group, id: " << g.id << ", group: " << g.name << logend;
|
|
|
|
iter = group_tab.PushBack( g );
|
|
last_id = g.id;
|
|
}
|
|
|
|
long user_id = AssertValueLong(r, i, cuser_id);
|
|
|
|
if( !IsNull(r, i, cuser_id) && user_id!=-1 && !group_tab.Empty() )
|
|
{
|
|
iter->members.push_back(user_id);
|
|
log << log3 << "Db: get group member: user_id: " << user_id << logend;
|
|
}
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
*/
|
|
|
|
|
|
} // namespace Winix
|
|
|