AdminUserEditForm.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using Npgsql;
  2. using System;
  3. using System.Configuration;
  4. using System.Data;
  5. using System.Windows.Forms;
  6. namespace WindowsFormsApp4
  7. {
  8. public partial class AdminUserEditForm : Form
  9. {
  10. private readonly string connStr = ConfigurationManager.ConnectionStrings["PostgreSQL"].ConnectionString;
  11. private int? userId = null;
  12. // Конструктор: если userId передан, то редактирование, иначе – добавление нового пользователя
  13. public AdminUserEditForm(int? userId = null)
  14. {
  15. InitializeComponent();
  16. this.userId = userId;
  17. LoadLibraries();
  18. if (userId.HasValue)
  19. {
  20. LoadUserData();
  21. txtUserId.Text = userId.Value.ToString();
  22. }
  23. else
  24. {
  25. this.Text = "Добавление пользователя";
  26. labelTitle.Text = "Добавление пользователя";
  27. txtUserId.Text = "(новый)";
  28. }
  29. }
  30. private string GenerateSalt()
  31. {
  32. byte[] saltBytes = new byte[16];
  33. using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())
  34. rng.GetBytes(saltBytes);
  35. return Convert.ToBase64String(saltBytes);
  36. }
  37. private string HashPassword(string password, string salt)
  38. {
  39. byte[] combined = System.Text.Encoding.UTF8.GetBytes(password + salt);
  40. using (var sha256 = System.Security.Cryptography.SHA256.Create())
  41. {
  42. byte[] hash = sha256.ComputeHash(combined);
  43. return Convert.ToBase64String(hash);
  44. }
  45. }
  46. private void LoadLibraries()
  47. {
  48. string query = "SELECT id, name FROM libraries ORDER BY name";
  49. DataTable dt = new DataTable();
  50. using (var conn = new NpgsqlConnection(connStr))
  51. using (var cmd = new NpgsqlCommand(query, conn))
  52. {
  53. conn.Open();
  54. using (var adapter = new NpgsqlDataAdapter(cmd))
  55. {
  56. adapter.Fill(dt);
  57. }
  58. }
  59. comboBoxLibrary.DisplayMember = "name";
  60. comboBoxLibrary.ValueMember = "id";
  61. comboBoxLibrary.DataSource = dt;
  62. comboBoxLibrary.SelectedIndex = -1;
  63. }
  64. private void LoadUserData()
  65. {
  66. string query = @"
  67. SELECT name, lastname, phone, email, role_name, library_id, bilet_active
  68. FROM users WHERE id = @id";
  69. using (var conn = new NpgsqlConnection(connStr))
  70. using (var cmd = new NpgsqlCommand(query, conn))
  71. {
  72. cmd.Parameters.AddWithValue("id", userId.Value);
  73. conn.Open();
  74. using (var reader = cmd.ExecuteReader())
  75. {
  76. if (reader.Read())
  77. {
  78. txtName.Text = reader["name"].ToString();
  79. txtLastname.Text = reader["lastname"].ToString();
  80. txtPhone.Text = reader["phone"].ToString();
  81. txtEmail.Text = reader["email"].ToString();
  82. comboBoxRole.SelectedItem = reader["role_name"].ToString();
  83. if (reader["library_id"] != DBNull.Value)
  84. comboBoxLibrary.SelectedValue = reader["library_id"];
  85. checkBoxActive.Checked = Convert.ToBoolean(reader["bilet_active"]);
  86. }
  87. }
  88. }
  89. }
  90. private void btnSave_Click(object sender, EventArgs e)
  91. {
  92. if (string.IsNullOrEmpty(txtName.Text) || string.IsNullOrEmpty(txtLastname.Text))
  93. {
  94. MessageBox.Show("Имя и фамилия обязательны", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  95. return;
  96. }
  97. string role = comboBoxRole.SelectedItem?.ToString();
  98. if (string.IsNullOrEmpty(role))
  99. {
  100. MessageBox.Show("Выберите роль", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  101. return;
  102. }
  103. object libraryId = comboBoxLibrary.SelectedValue ?? DBNull.Value;
  104. // Обработка пароля (только если поле видимо и в нём что-то есть)
  105. string newPassword = txtNewPassword?.Text.Trim();
  106. bool updatePassword = !string.IsNullOrEmpty(newPassword);
  107. if (updatePassword && newPassword != txtConfirmPassword?.Text.Trim())
  108. {
  109. MessageBox.Show("Пароль и подтверждение не совпадают", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  110. return;
  111. }
  112. if (updatePassword && newPassword.Length < 4)
  113. {
  114. MessageBox.Show("Пароль должен быть не менее 4 символов", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  115. return;
  116. }
  117. try
  118. {
  119. using (var conn = new NpgsqlConnection(connStr))
  120. {
  121. conn.Open();
  122. if (userId.HasValue)
  123. {
  124. // 1. Обновление данных пользователя
  125. string query = @"
  126. UPDATE users
  127. SET name=@name, lastname=@lastname, phone=@phone, email=@email,
  128. role_name=@role::role, library_id=@libId, bilet_active=@active
  129. WHERE id=@id";
  130. using (var cmd = new NpgsqlCommand(query, conn))
  131. {
  132. cmd.Parameters.AddWithValue("name", txtName.Text);
  133. cmd.Parameters.AddWithValue("lastname", txtLastname.Text);
  134. cmd.Parameters.AddWithValue("phone", txtPhone.Text);
  135. cmd.Parameters.AddWithValue("email", txtEmail.Text);
  136. cmd.Parameters.AddWithValue("role", role);
  137. cmd.Parameters.AddWithValue("libId", libraryId == DBNull.Value ? DBNull.Value : libraryId);
  138. cmd.Parameters.AddWithValue("active", checkBoxActive.Checked);
  139. cmd.Parameters.AddWithValue("id", userId.Value);
  140. cmd.ExecuteNonQuery();
  141. }
  142. // 2. Если задан новый пароль – обновляем user_auth
  143. if (updatePassword)
  144. {
  145. string salt = GenerateSalt();
  146. string hash = HashPassword(newPassword, salt);
  147. string authQuery = @"
  148. UPDATE user_auth
  149. SET password = @hash, salt = @salt
  150. WHERE user_id = @userId";
  151. using (var cmd = new NpgsqlCommand(authQuery, conn))
  152. {
  153. cmd.Parameters.AddWithValue("hash", hash);
  154. cmd.Parameters.AddWithValue("salt", salt);
  155. cmd.Parameters.AddWithValue("userId", userId.Value);
  156. if (cmd.ExecuteNonQuery() == 0)
  157. {
  158. // Если записи ещё нет (бывает при ручной миграции), вставляем
  159. string insertAuth = @"
  160. INSERT INTO user_auth (user_id, login, password, salt)
  161. VALUES (@userId, @login, @hash, @salt)";
  162. using (var cmd2 = new NpgsqlCommand(insertAuth, conn))
  163. {
  164. cmd2.Parameters.AddWithValue("userId", userId.Value);
  165. cmd2.Parameters.AddWithValue("login", txtEmail.Text);
  166. cmd2.Parameters.AddWithValue("hash", hash);
  167. cmd2.Parameters.AddWithValue("salt", salt);
  168. cmd2.ExecuteNonQuery();
  169. }
  170. }
  171. }
  172. }
  173. }
  174. else
  175. {
  176. // Добавление нового пользователя
  177. if (!updatePassword)
  178. {
  179. MessageBox.Show("Для нового пользователя необходимо задать пароль", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  180. return;
  181. }
  182. // Вставка в users
  183. string insertUser = @"
  184. INSERT INTO users (name, lastname, phone, email, registration_date, role_name, library_id, bilet_active)
  185. VALUES (@name, @lastname, @phone, @email, CURRENT_DATE, @role::role, @libId, @active)
  186. RETURNING id";
  187. int newId;
  188. using (var cmd = new NpgsqlCommand(insertUser, conn))
  189. {
  190. cmd.Parameters.AddWithValue("name", txtName.Text);
  191. cmd.Parameters.AddWithValue("lastname", txtLastname.Text);
  192. cmd.Parameters.AddWithValue("phone", txtPhone.Text);
  193. cmd.Parameters.AddWithValue("email", txtEmail.Text);
  194. cmd.Parameters.AddWithValue("role", role);
  195. cmd.Parameters.AddWithValue("libId", libraryId == DBNull.Value ? DBNull.Value : libraryId);
  196. cmd.Parameters.AddWithValue("active", checkBoxActive.Checked);
  197. newId = (int)cmd.ExecuteScalar();
  198. }
  199. // Вставка в user_auth
  200. string salt = GenerateSalt();
  201. string hash = HashPassword(newPassword, salt);
  202. string insertAuth = @"
  203. INSERT INTO user_auth (user_id, login, password, salt)
  204. VALUES (@userId, @login, @hash, @salt)";
  205. using (var cmd = new NpgsqlCommand(insertAuth, conn))
  206. {
  207. cmd.Parameters.AddWithValue("userId", newId);
  208. cmd.Parameters.AddWithValue("login", txtEmail.Text); // логин = email (можно изменить)
  209. cmd.Parameters.AddWithValue("hash", hash);
  210. cmd.Parameters.AddWithValue("salt", salt);
  211. cmd.ExecuteNonQuery();
  212. }
  213. MessageBox.Show($"Пользователь добавлен с ID {newId}", "Успех");
  214. }
  215. MessageBox.Show("Сохранено", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
  216. this.DialogResult = DialogResult.OK;
  217. this.Close();
  218. }
  219. }
  220. catch (Exception ex)
  221. {
  222. MessageBox.Show($"Ошибка: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
  223. }
  224. }
  225. private void btnCancel_Click(object sender, EventArgs e)
  226. {
  227. this.DialogResult = DialogResult.Cancel;
  228. this.Close();
  229. }
  230. private void AdminUserEditForm_Load(object sender, EventArgs e)
  231. {
  232. }
  233. private void labelConfirmPassword_Click(object sender, EventArgs e)
  234. {
  235. }
  236. }
  237. }