whole project pushed

This commit is contained in:
2025-08-23 16:13:20 +03:30
parent 1cbde63229
commit 76a1e32e34
36 changed files with 1798 additions and 315 deletions

View File

@ -59,5 +59,16 @@ namespace boilerplate.Areas.HelpPage.Controllers
return View(ErrorViewName); return View(ErrorViewName);
} }
public class UserController : Controller
{
// ???? ?????? ??? ?? ??? ?????? ...
// ??? ??? ?? ????? ????
public ActionResult AllNews()
{
return View();
}
}
} }
} }

View File

@ -1,6 +1,10 @@
using System; // Make sure these 'using' directives are at the top of your file
using boilerplate.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Entity; // This is required for .ToListAsync()
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
@ -8,10 +12,24 @@ namespace boilerplate.Controllers
{ {
public class HomeController : Controller public class HomeController : Controller
{ {
// Add an instance of your database context
private boilerplateEntities db = new boilerplateEntities();
// GET: Default // GET: Default
public ActionResult Index() public ActionResult Index()
{ {
return View(); return View();
} }
// This action now fetches news from the database
public async Task<ActionResult> AllNews()
{
// Fetch all news, order by the most recent ones
var newsList = await db.News.OrderByDescending(n => n.News_Date).ToListAsync();
return View(newsList);
}
} }
} }

View File

@ -1,20 +1,17 @@
using boilerplate.Models; using boilerplate.Models;
using Microsoft.Ajax.Utilities;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Entity; using System.Data.Entity;
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder; using System.Data.Entity.Validation;
using System.Data.Entity.Infrastructure; using System.IO;
using System.Data.Entity.SqlServer;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Reflection; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.UI.WebControls; using ClosedXML.Excel;
namespace boilerplate.Controllers namespace boilerplate.Controllers
{ {
@ -28,236 +25,322 @@ namespace boilerplate.Controllers
if (!HasSession()) { return RedirectToAction("Login"); } if (!HasSession()) { return RedirectToAction("Login"); }
if (HasSession("ManageDashboard")) if (HasSession("ManageDashboard"))
{ {
var user = Session["User"] as User;
ViewBag.Title = "داشبورد"; ViewBag.Title = "داشبورد";
ViewBag.Counter1 = db.Users.Count();
ViewBag.Counter2 = db.Users.Count();
ViewBag.Counter3 = db.Users.Count();
ViewBag.Counter4 = db.Users.Count();
ViewBag.Counter5 = db.Users.Count();
ViewBag.Counter6 = db.Users.Count();
} }
return View(); return View();
} }
// --- User Management Actions ---
public async Task<ActionResult> Users() public async Task<ActionResult> Users()
{ {
List<UserModel> models = new List<UserModel>();
if (!HasSession("ManageUser")) { return RedirectToAction("Index"); } if (!HasSession("ManageUser")) { return RedirectToAction("Index"); }
models = db.Users.AsNoTracking().Select(x => new UserModel var models = await db.Users.AsNoTracking().Select(x => new UserModel
{ {
Id = x.User_Id, Id = x.User_Id,
Name = x.User_Name, Name = x.User_Name,
Family = x.User_Family, Family = x.User_Family,
Phone = x.User_Phone, Phone = x.User_Phone,
Code = x.User_Code,
Status = x.User_Status,
Role = x.User_Role, Role = x.User_Role,
Status = x.User_Status,
CreatedDate = x.User_CreatedDateFa CreatedDate = x.User_CreatedDateFa
}).ToList(); }).ToListAsync();
return View(models); return View(models);
} }
public new async Task<ActionResult> User(int Id = 0) public new async Task<ActionResult> User(int Id = 0)
{ {
if (!HasSession("ManageUser")) { return new HttpStatusCodeResult(HttpStatusCode.Unauthorized); } if (!HasSession("ManageUser")) { return new HttpStatusCodeResult(HttpStatusCode.Unauthorized); }
var model = new User()
{
User_Id = Id,
User_Status = 1,
User_Image = "dUser.png"
};
if (Id != 0)
{
User model;
model = db.Users.AsNoTracking().Where(x => x.User_Id == Id).FirstOrDefault(); if (Id == 0)
{
model = new User() { User_Id = 0, User_Status = 1, User_Image = "dUser.png" };
}
else
{
model = await db.Users.AsNoTracking().FirstOrDefaultAsync(x => x.User_Id == Id);
if (model == null) { return RedirectToAction("Users"); } if (model == null) { return RedirectToAction("Users"); }
} }
return View(model); return View(model);
} }
[Route("~/panel/Setting")] // --- News Management Actions (Reverted to simple version) ---
public async Task<ActionResult> Setting() public async Task<ActionResult> NewsList()
{ {
if (!HasSession("ManageNews")) { return RedirectToAction("Index"); }
var model = new Setting() var news = await db.News.OrderByDescending(n => n.News_Date).ToListAsync();
return View(news);
}
// --- News Management Actions ---
// --- News Management Actions ---
public class AddNewsViewModel
{ {
Setting_Id = 1, public News News { get; set; }
Setting_Social = "[]", public List<Item> AllCategories { get; set; }
Setting_Send = false, public List<Item> AllTags { get; set; }
}
public async Task<ActionResult> AddNews(int id = 0)
{
if (!HasSession("ManageNews")) { return RedirectToAction("Index"); }
var allItems = await db.Items.ToListAsync();
var categories = allItems.Where(i => i.Item_Type == "1").ToList();
var tags = allItems.Where(i => i.Item_Type == "2").ToList();
var viewModel = new AddNewsViewModel
{
AllCategories = categories,
AllTags = tags
}; };
if (!HasSession("ManageSetting")) { return RedirectToAction("Index"); }
model = db.Settings.AsNoTracking().FirstOrDefault(); if (id == 0)
{
return View(model); ViewBag.PageTitle = "افزودن خبر جدید";
viewModel.News = new News { News_Date = DateTime.Now };
}
else
{
var news = await db.News.FindAsync(id);
if (news == null) { return HttpNotFound(); }
ViewBag.PageTitle = "ویرایش خبر";
viewModel.News = news;
} }
[Route("~/panel/SaveSettings")] return View(viewModel);
[HttpPost]
public async Task<JsonResult> SaveSettings()
{
StatusModel statusModel = new StatusModel() { Status = "Success" };
try
{
if (HasSession())
{
var User = Session["User"] as User;
if (HasSession("ManageSetting")
)
{
SettingModel model = JsonConvert.DeserializeObject<SettingModel>(Request.Form["Model"]);
var Settings = await db.Settings.FirstOrDefaultAsync();
if (Settings != null)
{
Settings.Setting_Name = model.Name;
Settings.Setting_Title = model.Title;
Settings.Setting_Discount = model.Discount;
Settings.Setting_Description = model.Description;
Settings.Setting_Keywords = model.Keywords;
Settings.Setting_Footer = model.Footer;
Settings.Setting_Header = model.Header;
Settings.Setting_Social = JsonConvert.SerializeObject(model.Socials);
Settings.Setting_Username = model.SmsUsername;
Settings.Setting_Password = model.SmsPassword;
Settings.Setting_FromNumber = model.SmsFromNumber;
Settings.Setting_PaternLogin = model.SmsPaternLogin;
Settings.Setting_Address = model.address;
Settings.Setting_PostCode = model.postcode;
Settings.Setting_Phone = model.phone;
Settings.Setting_Website = model.website;
db.Entry(Settings).State = EntityState.Modified;
for (int i = 0; i < Request.Files.Count; i++)
{
switch (Request.Files.AllKeys[i])
{
case "Logo":
Request.Files[i].SaveAs(Server.MapPath($"~/Media/logo.png"));
break;
case "Icon":
Request.Files[i].SaveAs(Server.MapPath($"~/Media/favicon.ico"));
break;
} }
}
}
}
}
else { statusModel.Status = "Auth"; }
}
catch { statusModel.Status = "Error"; }
return Json(statusModel);
}
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<JsonResult> Login(LoginModel model) [ValidateInput(false)]
public async Task<ActionResult> AddNews(AddNewsViewModel viewModel, HttpPostedFileBase imageFile, string[] selectedCategories, string[] selectedTags)
{ {
StatusModel statusModel = new StatusModel() { Status = "Success" }; if (!HasSession("ManageNews")) { return RedirectToAction("Index"); }
// Join multiple selections into comma-separated strings
viewModel.News.News_Category = selectedCategories != null ? string.Join(",", selectedCategories) : "";
viewModel.News.News_Tag = selectedTags != null ? string.Join(",", selectedTags) : "";
// *** ADDED: Server-side validation for required fields ***
if (viewModel.News.News_ID == 0 && (imageFile == null || imageFile.ContentLength == 0))
{
ModelState.AddModelError("imageFile", "لطفاً یک تصویر برای خبر انتخاب کنید.");
}
if (selectedCategories == null || !selectedCategories.Any())
{
ModelState.AddModelError("selectedCategories", "انتخاب حداقل یک دسته‌بندی الزامی است.");
}
if (selectedTags == null || !selectedTags.Any())
{
ModelState.AddModelError("selectedTags", "انتخاب حداقل یک تگ الزامی است.");
}
try try
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
if (!string.IsNullOrEmpty(model.Username) && !string.IsNullOrEmpty(model.Password)) var model = viewModel.News;
if (imageFile != null && imageFile.ContentLength > 0)
{ {
var User = await db.Users.Where(x => x.User_Phone == model.Username && x.User_Role == "Admin").FirstOrDefaultAsync(); var uploadDir = "~/Media/News";
if (User != null) if (!Directory.Exists(Server.MapPath(uploadDir)))
{ {
if (User.User_Status == 1) Directory.CreateDirectory(Server.MapPath(uploadDir));
}
var fileName = Guid.NewGuid().ToString() + Path.GetExtension(imageFile.FileName);
var path = Path.Combine(Server.MapPath(uploadDir), fileName);
imageFile.SaveAs(path);
model.News_IMG = fileName;
}
if (model.News_ID == 0)
{ {
if (User.User_Password == functions.HashPassword(model.Password + User.User_CreatedDate)) model.News_CreateDate = DateTime.Now;
model.News_Date = DateTime.Now;
db.News.Add(model);
}
else
{ {
DateTime Now = DateTime.Now; model.News_EditDate = DateTime.Now;
string Token = functions.GenerateToken(); db.Entry(model).State = EntityState.Modified;
User.User_LoginDate = Now; if (imageFile == null)
User.User_LoginDateFa = functions.ConvertToPersianDate(Now); {
User.User_Token = Token; db.Entry(model).Property(x => x.News_IMG).IsModified = false;
}
}
await db.SaveChangesAsync(); await db.SaveChangesAsync();
Session["User"] = User; return RedirectToAction("NewsList");
SetCookie("UserId", $"{User.User_Id}"); }
SetCookie("Token", Token); }
catch (Exception ex)
{
ModelState.AddModelError("", "یک خطای پیش‌بینی نشده رخ داد: " + ex.Message);
}
// If we get here, something failed. Repopulate the dropdowns.
var allItems = await db.Items.ToListAsync();
viewModel.AllCategories = allItems.Where(i => i.Item_Type == "1").ToList();
viewModel.AllTags = allItems.Where(i => i.Item_Type == "2").ToList();
return View(viewModel);
}
[HttpPost]
public async Task<JsonResult> DeleteNews(int id)
{
if (!HasSession("ManageNews")) { return Json(new { success = false }); }
var news = await db.News.FindAsync(id);
if (news != null)
{
var imagePath = Server.MapPath("~/Media/News/" + news.News_IMG);
if (System.IO.File.Exists(imagePath))
{
System.IO.File.Delete(imagePath);
}
db.News.Remove(news);
await db.SaveChangesAsync();
return Json(new { success = true });
}
return Json(new { success = false });
}
// --- Item (Category/Tag) Management Actions ---
public async Task<ActionResult> Items(int id)
{
if (!HasSession("ManageItems")) { return RedirectToAction("Index"); }
string itemTypeString = id.ToString();
ViewBag.ItemType = id;
ViewBag.PageTitle = (id == 1) ? "مدیریت دسته‌بندی‌ها" : "مدیریت تگ‌ها";
ViewBag.NewItemLabel = (id == 1) ? "نام دسته‌بندی جدید" : "نام تگ جدید";
var items = await db.Items.Where(i => i.Item_Type == itemTypeString).ToListAsync();
return View(items);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddItem(Item model)
{
if (!HasSession("ManageItems")) { return RedirectToAction("Index"); }
if (ModelState.IsValid && !string.IsNullOrWhiteSpace(model.Item_Title))
{
bool exists = await db.Items.AnyAsync(i => i.Item_Title == model.Item_Title && i.Item_Type == model.Item_Type);
if (!exists)
{
db.Items.Add(model);
await db.SaveChangesAsync();
}
}
return RedirectToAction("Items", new { id = Convert.ToInt32(model.Item_Type) });
}
[HttpPost]
public async Task<JsonResult> DeleteItem(int id)
{
if (!HasSession("ManageItems")) { return Json(new { success = false }); }
var item = await db.Items.FindAsync(id);
if (item != null)
{
db.Items.Remove(item);
await db.SaveChangesAsync();
return Json(new { success = true });
}
return Json(new { success = false });
}
// --- Settings Action ---
[Route("~/panel/Setting")]
public async Task<ActionResult> Setting()
{
if (!HasSession("ManageSetting")) { return RedirectToAction("Index"); }
var model = await db.Settings.AsNoTracking().FirstOrDefaultAsync();
if (model == null)
{
model = new Setting();
}
return View(model);
}
// --- Authentication and Session Management ---
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Login(LoginModel model)
{
StatusModel statusModel = new StatusModel() { Status = "Success", RedirectUrl = "" };
try
{
if (ModelState.IsValid && !string.IsNullOrEmpty(model.Username) && !string.IsNullOrEmpty(model.Password))
{
var user = await db.Users.FirstOrDefaultAsync(x => x.User_Phone == model.Username);
if (user != null && user.User_Status == 1)
{
if (string.Equals(user.User_Role, "Admin", StringComparison.OrdinalIgnoreCase) &&
user.User_Password == functions.HashPassword(model.Password + user.User_CreatedDate))
{
Session["User"] = user;
SetCookie("UserId", $"{user.User_Id}");
SetCookie("Token", functions.GenerateToken());
statusModel.RedirectUrl = "/Panel/Index";
} }
else { statusModel.Status = "Wrong"; } else { statusModel.Status = "Wrong"; }
} }
else { statusModel.Status = "Block"; } else if (user != null) { statusModel.Status = "Block"; }
}
else { statusModel.Status = "NoExist"; } else { statusModel.Status = "NoExist"; }
} }
else { statusModel.Status = "Empty"; } else { statusModel.Status = "Empty"; }
} }
else { statusModel.Status = "NotValid"; }
}
catch { statusModel.Status = "Error"; } catch { statusModel.Status = "Error"; }
return Json(statusModel);
}
[Route("~/Panel/Logout")] return Json(statusModel);
public async Task Logout()
{
if (Session["User"] != null)
{
var UserModel = Session["User"] as User;
var Single = await db.Users.FindAsync(UserModel.User_Id);
if (Single != null)
{
Single.User_Token = null;
await db.SaveChangesAsync();
}
}
Session.Clear();
Session.Abandon();
SetCookie("UserId", "", -1);
SetCookie("UserToken", "", -1);
Response.Redirect("~/Panel/Login");
}
[Route("~/Login")]
[Route("Login")]
public async Task<ActionResult> Login(string Return = "")
{
ViewBag.Return = Return;
if (Session["User"] != null)
{
Response.Redirect("~/panel/index");
}
else if (UserSessionExists()) { Response.Redirect("~/panel/Index"); }
return View();
} }
bool UserSessionExists() bool UserSessionExists()
{ {
try try
{ {
string Token = GetCookie("Token"); string tokenFromCookie = GetCookie("Token");
decimal.TryParse(GetCookie("UserId"), out decimal UserId); string userIdFromCookie = GetCookie("UserId");
if (!string.IsNullOrEmpty(Token) && UserId != 0)
if (string.IsNullOrEmpty(tokenFromCookie) || string.IsNullOrEmpty(userIdFromCookie))
{ {
var Single = db.Users.Where(x => x.User_Id == UserId && x.User_Token == Token && x.User_Status == 1 && x.User_Role == "Admin").FirstOrDefault(); return false;
if (Single != null) }
if (!int.TryParse(userIdFromCookie, out int userId))
{ {
Session["User"] = Single; return false;
}
var user = db.Users.FirstOrDefault(x => x.User_Id == userId && x.User_Token == tokenFromCookie && x.User_Status == 1);
if (user != null && user.User_Role != null && string.Equals(user.User_Role.Trim(), "Admin", StringComparison.OrdinalIgnoreCase))
{
Session["User"] = user;
return true;
} }
else else
{ {
SetCookie("Token", "", -1); SetCookie("Token", "", -1);
SetCookie("UserId", "", -1); SetCookie("UserId", "", -1);
}
if (Session["User"] != null) { return true; }
}
SetCookie("Token", "", -1);
SetCookie("UserId", "", -1);
return false; return false;
} }
catch { return false; } }
catch
{
return false;
}
} }
bool HasSession(string Access = "") bool HasSession(string Access = "")
@ -266,107 +349,92 @@ namespace boilerplate.Controllers
return string.IsNullOrEmpty(Access) || functions.HasAccess((Session["User"] as User).User_Access, Access); return string.IsNullOrEmpty(Access) || functions.HasAccess((Session["User"] as User).User_Access, Access);
} }
[Route("~/Verify")] [Route("~/Panel/Logout")]
[Route("Verify")] public async Task Logout()
public ActionResult Verify(string Phone = "", string Return = "") {
Session.Clear();
Session.Abandon();
SetCookie("UserId", "", -1);
SetCookie("Token", "", -1);
Response.Redirect("~/Panel/Login");
}
[Route("~/Login")]
[Route("Login")]
public ActionResult Login(string Return = "")
{ {
ViewBag.Return = Return; ViewBag.Return = Return;
if (Session["User"] != null) if (UserSessionExists()) { Response.Redirect("~/panel/Index"); }
{
Response.Redirect("~/Index");
}
if (Phone == "")
{
Response.Redirect("~/Login");
}
else
{
ViewBag.Phone = Phone;
}
return View(); return View();
} }
//set session and cookies afte login
[HttpGet] [HttpGet]
[Route("Complete")] public ActionResult Complete(int User, string Token)
[Route("~/Complete")]
public ActionResult Complete()
{ {
try var user = db.Users.FirstOrDefault(u => u.User_Id == User && u.User_Token == Token);
if (user != null)
{ {
// Log query parameters Session["User"] = user;
var user = Request.QueryString["User"]; SetCookie("UserId", user.User_Id.ToString());
var token = Request.QueryString["Token"]; SetCookie("Token", user.User_Token);
return new HttpStatusCodeResult(HttpStatusCode.OK);
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(token))
{
Console.WriteLine("User or Token is missing in the query string.");
return new HttpStatusCodeResult(400, "Bad Request: User or Token missing.");
} }
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
// Log the query parameters
Console.WriteLine($"User: {user}, Token: {token}");
var currentuser = db.Users
.Where(x => x.User_Id.ToString() == user && x.User_Token.ToString() == token)
.FirstOrDefault();
if (currentuser != null)
{
// Perform necessary actions, like setting session and cookies
Session["User"] = currentuser;
SetCookie("UserId", $"{currentuser.User_Id}");
SetCookie("Token", currentuser.User_Token);
// Log success
Console.WriteLine("User authenticated and session updated.");
}
else
{
// Log if user is not found
Console.WriteLine("User not found.");
return new HttpStatusCodeResult(404, "User not found.");
}
}
catch (Exception ex)
{
// Log error details
Console.WriteLine($"Error in Complete: {ex.Message}");
return new HttpStatusCodeResult(500, "Internal Server Error: " + ex.Message);
}
// Return a success response or redirect
return new HttpStatusCodeResult(200, "Request completed successfully.");
} }
string SetCookie(string Key, string Value, int ExpireDay = 365) string SetCookie(string Key, string Value, int ExpireDay = 365)
{ {
try var cookie = new HttpCookie(Key, Value)
{ {
Response.Cookies.Add(new HttpCookie(Key, Value) { Expires = DateTime.Now.AddDays(ExpireDay) }); Expires = DateTime.Now.AddDays(ExpireDay),
} Path = "/",
catch { } SameSite = SameSiteMode.Lax
};
Response.Cookies.Add(cookie);
return Value; return Value;
} }
string GetCookie(string Key) string GetCookie(string Key)
{
string value = string.Empty;
try
{ {
var cookie = Request.Cookies[Key]; var cookie = Request.Cookies[Key];
if (cookie != null) return cookie?.Value ?? string.Empty;
}
[HttpPost]
public async Task<JsonResult> UpdateItem(int id, string newTitle)
{ {
if (string.IsNullOrWhiteSpace(cookie.Value)) if (!HasSession("ManageItems")) { return Json(new { success = false, message = "Unauthorized" }); }
if (string.IsNullOrWhiteSpace(newTitle))
{ {
return value; return Json(new { success = false, message = "نام آیتم نمی‌تواند خالی باشد." });
} }
value = cookie.Value;
var item = await db.Items.FindAsync(id);
if (item != null)
{
// بررسی برای جلوگیری از ثبت نام تکراری
bool exists = await db.Items.AnyAsync(i => i.Item_Title == newTitle && i.Item_Type == item.Item_Type && i.Item_Id != id);
if (exists)
{
return Json(new { success = false, message = "این نام قبلاً ثبت شده است." });
} }
item.Item_Title = newTitle;
await db.SaveChangesAsync();
return Json(new { success = true });
} }
catch { } return Json(new { success = false, message = "آیتم یافت نشد." });
return value;
} }
public async Task<ActionResult> ClientManagement()
{
if (!HasSession("ManageClients")) { return RedirectToAction("Index"); }
var clients = await db.Clients.ToListAsync();
return View(clients);
}
} }
} }

View File

@ -1,4 +1,5 @@
using boilerplate.Models; using boilerplate.Models;
using ClosedXML.Excel;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -9,11 +10,13 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using System.Web.Http; using System.Web.Http;
namespace boilerplate.Controllers namespace boilerplate.Controllers
{ {
public class UserController : ApiController public class UserController : ApiController
@ -275,6 +278,7 @@ namespace boilerplate.Controllers
Token = Token, Token = Token,
Id = user.User_Id, Id = user.User_Id,
Phone = user.User_Phone, Phone = user.User_Phone,
role = user.User_Role,
}); });
} }
else else
@ -319,5 +323,237 @@ namespace boilerplate.Controllers
} }
return statusModel; return statusModel;
} }
[Route("api/Client/Import")]
[HttpPost]
public async Task<StatusModel> ImportClients()
{
var statusModel = new StatusModel { Status = "Success" };
try
{
if (!Request.Content.IsMimeMultipartContent())
{
statusModel.Status = "InvalidRequest";
return statusModel;
}
var provider = await Request.Content.ReadAsMultipartAsync(new InMemoryMultipartFormDataStreamProvider());
var formData = provider.FormData;
// ۱. احراز هویت و بررسی دسترسی
var authModel = JsonConvert.DeserializeObject<AuthModel>(formData.Get("Auth"));
var userAccessModel = functions.CheckUserAccess(authModel, new string[] { "Admin" }, new string[] { "All", "ManageClients" });
if (userAccessModel.Id == 0)
{
statusModel.Status = "Auth";
return statusModel;
}
// ۲. دریافت فایل اکسل
if (provider.Files.Count == 0)
{
statusModel.Status = "NoFile";
return statusModel;
}
HttpContent excelFile = provider.Files[0];
Stream excelStream = await excelFile.ReadAsStreamAsync();
// ۳. پردازش فایل اکسل با ClosedXML
using (var workbook = new XLWorkbook(excelStream))
{
var worksheet = workbook.Worksheet(1);
var rows = worksheet.RowsUsed().Skip(1); // نادیده گرفتن هدر
var clientsToAdd = new List<Client>();
foreach (var row in rows)
{
if (row.Cell(1).IsEmpty()) continue;
clientsToAdd.Add(new Client
{
Client_Name = row.Cell(1).GetValue<string>(),
Client_LastName = row.Cell(2).GetValue<string>(),
Client_PhoneNumber = row.Cell(3).GetValue<string>(),
Client_UserName = row.Cell(4).GetValue<string>(),
Client_Email = row.Cell(5).GetValue<string>()
});
}
// ۴. ذخیره در دیتابیس
if (clientsToAdd.Any())
{
db.Clients.AddRange(clientsToAdd);
await db.SaveChangesAsync();
statusModel.Message = $"تعداد {clientsToAdd.Count} مشتری جدید با موفقیت اضافه شد.";
}
else
{
statusModel.Status = "EmptyFile";
statusModel.Message = "فایل اکسل خالی است یا ردیف معتبری ندارد.";
}
}
}
catch (Exception ex)
{
statusModel.Status = "Error";
statusModel.Message = ex.ToString(); // برگرداندن خطای کامل برای دیباگ
}
return statusModel;
}
[Route("api/Client/Export")]
[HttpPost]
public async Task<HttpResponseMessage> ExportClients([FromBody] AuthModel authModel)
{
// ۱. احراز هویت و بررسی دسترسی
var userAccessModel = functions.CheckUserAccess(authModel, new string[] { "Admin" }, new string[] { "All", "ManageClients" });
if (userAccessModel.Id == 0)
{
return Request.CreateResponse(HttpStatusCode.Unauthorized);
}
// ۲. دریافت لیست مشتریان
var clients = await db.Clients.ToListAsync();
// ۳. ساخت فایل اکسل در حافظه
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add("Clients");
worksheet.Cell(1, 1).Value = "نام";
worksheet.Cell(1, 2).Value = "نام خانوادگی";
worksheet.Cell(1, 3).Value = "شماره تلفن";
worksheet.Cell(1, 4).Value = "نام کاربری";
worksheet.Cell(1, 5).Value = "ایمیل";
worksheet.Row(1).Style.Font.Bold = true;
worksheet.Cell(2, 1).InsertData(clients);
// ۴. آماده‌سازی پاسخ برای دانلود
using (var stream = new MemoryStream())
{
workbook.SaveAs(stream);
var content = stream.ToArray();
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(content)
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"Clients_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
};
return result;
}
}
}
[Route("api/Client/Delete")]
[HttpPost]
public async Task<StatusModel> DeleteClient(AuthModel model)
{
StatusModel statusModel = new StatusModel() { Status = "Success" };
try
{
// Check for admin privileges
var userAccessModel = functions.CheckUserAccess(model, new string[] { "Admin" }, new string[] { "All", "ManageClients" });
if (userAccessModel.Id == 0)
{
statusModel.Status = "Auth";
return statusModel;
}
// Find and delete the client
var clientToDelete = await db.Clients.FindAsync(model.Id);
if (clientToDelete != null)
{
db.Clients.Remove(clientToDelete);
await db.SaveChangesAsync();
}
else
{
statusModel.Status = "NotFound";
}
}
catch (Exception ex)
{
statusModel.Status = "Error";
statusModel.Message = ex.Message;
}
return statusModel;
}
// --- این کلاس مدل را به فایل Models/UserModel.cs یا یک فایل جدید اضافه کنید ---
public class ClientUpdateModel
{
public AuthModel Auth { get; set; }
public Client Client { get; set; }
}
// --- این متدها را به UserController.cs اضافه کنید ---
// API برای دریافت اطلاعات یک مشتری خاص (برای نمایش در فرم ویرایش)
[Route("api/Client/Get/{id}")]
[HttpPost]
public async Task<HttpResponseMessage> GetClient(int id, [FromBody] AuthModel authModel)
{
var userAccessModel = functions.CheckUserAccess(authModel, new string[] { "Admin" }, new string[] { "All", "ManageClients" });
if (userAccessModel.Id == 0)
{
return Request.CreateResponse(HttpStatusCode.Unauthorized);
}
var client = await db.Clients.FindAsync(id);
if (client == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
return Request.CreateResponse(HttpStatusCode.OK, client);
}
// API برای آپدیت اطلاعات یک مشتری
[Route("api/Client/Update")]
[HttpPost]
public async Task<StatusModel> UpdateClient([FromBody] ClientUpdateModel model)
{
var statusModel = new StatusModel { Status = "Success" };
try
{
var userAccessModel = functions.CheckUserAccess(model.Auth, new string[] { "Admin" }, new string[] { "All", "ManageClients" });
if (userAccessModel.Id == 0)
{
statusModel.Status = "Auth";
return statusModel;
}
var clientToUpdate = await db.Clients.FindAsync(model.Client.Client_Id);
if (clientToUpdate != null)
{
// آپدیت کردن فیلدها
clientToUpdate.Client_Name = model.Client.Client_Name;
clientToUpdate.Client_LastName = model.Client.Client_LastName;
clientToUpdate.Client_PhoneNumber = model.Client.Client_PhoneNumber;
clientToUpdate.Client_UserName = model.Client.Client_UserName;
clientToUpdate.Client_Email = model.Client.Client_Email;
await db.SaveChangesAsync();
}
else
{
statusModel.Status = "NotFound";
}
}
catch (Exception ex)
{
statusModel.Status = "Error";
statusModel.Message = ex.Message;
}
return statusModel;
}
} }
} }

View File

@ -13,6 +13,8 @@ namespace boilerplate
{ {
protected void Application_Start() protected void Application_Start()
{ {
// خط کد قبلی که باعث خطا می‌شد، حذف شده است.
AreaRegistration.RegisterAllAreas(); AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register); GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

BIN
Media/User/dUser.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

24
Models/Client.cs Normal file
View File

@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace boilerplate.Models
{
using System;
using System.Collections.Generic;
public partial class Client
{
public int Client_Id { get; set; }
public string Client_Name { get; set; }
public string Client_LastName { get; set; }
public string Client_PhoneNumber { get; set; }
public string Client_UserName { get; set; }
public string Client_Email { get; set; }
}
}

21
Models/Item.cs Normal file
View File

@ -0,0 +1,21 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace boilerplate.Models
{
using System;
using System.Collections.Generic;
public partial class Item
{
public int Item_Id { get; set; }
public string Item_Title { get; set; }
public string Item_Type { get; set; }
}
}

View File

@ -25,6 +25,9 @@ namespace boilerplate.Models
throw new UnintentionalCodeFirstException(); throw new UnintentionalCodeFirstException();
} }
public virtual DbSet<Client> Clients { get; set; }
public virtual DbSet<Item> Items { get; set; }
public virtual DbSet<News> News { get; set; }
public virtual DbSet<Setting> Settings { get; set; } public virtual DbSet<Setting> Settings { get; set; }
public virtual DbSet<User> Users { get; set; } public virtual DbSet<User> Users { get; set; }
} }

View File

@ -1,4 +1,4 @@
// T4 code generation is enabled for model 'D:\Users\l\source\repos\boilerplate\Models\Model1.edmx'. // T4 code generation is enabled for model 'C:\Users\Senat\source\repos\boilerPlate - Test\new-boilerplate\Models\Model1.edmx'.
// To enable legacy code generation, change the value of the 'Code Generation Strategy' designer // To enable legacy code generation, change the value of the 'Code Generation Strategy' designer
// property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model // property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model
// is open in the designer. // is open in the designer.

View File

@ -5,6 +5,40 @@
<!-- SSDL content --> <!-- SSDL content -->
<edmx:StorageModels> <edmx:StorageModels>
<Schema Namespace="boilerplateModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2012" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl"> <Schema Namespace="boilerplateModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2012" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">
<EntityType Name="Client">
<Key>
<PropertyRef Name="Client_Id" />
</Key>
<Property Name="Client_Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="Client_Name" Type="nvarchar(max)" Nullable="false" />
<Property Name="Client_LastName" Type="nvarchar(max)" Nullable="false" />
<Property Name="Client_PhoneNumber" Type="nvarchar" MaxLength="50" Nullable="false" />
<Property Name="Client_UserName" Type="nvarchar" MaxLength="50" Nullable="false" />
<Property Name="Client_Email" Type="nvarchar" MaxLength="50" Nullable="false" />
</EntityType>
<EntityType Name="Item">
<Key>
<PropertyRef Name="Item_Id" />
</Key>
<Property Name="Item_Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="Item_Title" Type="nvarchar(max)" Nullable="false" />
<Property Name="Item_Type" Type="nvarchar(max)" Nullable="false" />
</EntityType>
<EntityType Name="News">
<Key>
<PropertyRef Name="News_ID" />
</Key>
<Property Name="News_ID" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="News_Title" Type="nvarchar" MaxLength="100" Nullable="false" />
<Property Name="News_Description" Type="nvarchar(max)" Nullable="false" />
<Property Name="News_Summary" Type="nvarchar(max)" Nullable="false" />
<Property Name="News_Category" Type="nvarchar(max)" Nullable="false" />
<Property Name="News_Tag" Type="nvarchar(max)" Nullable="false" />
<Property Name="News_Date" Type="datetime2" Precision="7" Nullable="false" />
<Property Name="News_CreateDate" Type="datetime2" Precision="7" Nullable="false" />
<Property Name="News_EditDate" Type="datetime2" Precision="7" />
<Property Name="News_IMG" Type="nvarchar(max)" Nullable="false" />
</EntityType>
<EntityType Name="Setting"> <EntityType Name="Setting">
<Key> <Key>
<PropertyRef Name="Setting_Id" /> <PropertyRef Name="Setting_Id" />
@ -53,14 +87,57 @@
<Property Name="User_LoginDateFa" Type="nvarchar" MaxLength="50" /> <Property Name="User_LoginDateFa" Type="nvarchar" MaxLength="50" />
</EntityType> </EntityType>
<EntityContainer Name="boilerplateModelStoreContainer"> <EntityContainer Name="boilerplateModelStoreContainer">
<EntitySet Name="Client" EntityType="Self.Client" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Item" EntityType="Self.Item" Schema="dbo" store:Type="Tables" />
<EntitySet Name="News" EntityType="Self.News" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Setting" EntityType="Self.Setting" Schema="dbo" store:Type="Tables" /> <EntitySet Name="Setting" EntityType="Self.Setting" Schema="dbo" store:Type="Tables" />
<EntitySet Name="User" EntityType="Self.User" Schema="dbo" store:Type="Tables" /> <EntitySet Name="User" EntityType="Self.User" Schema="dbo" store:Type="Tables" />
</EntityContainer> </EntityContainer>
</Schema> </Schema></edmx:StorageModels>
</edmx:StorageModels>
<!-- CSDL content --> <!-- CSDL content -->
<edmx:ConceptualModels> <edmx:ConceptualModels>
<Schema Namespace="boilerplateModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm"> <Schema Namespace="boilerplateModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
<EntityContainer Name="boilerplateEntities" annotation:LazyLoadingEnabled="true">
<EntitySet Name="Clients" EntityType="boilerplateModel.Client" />
<EntitySet Name="Items" EntityType="boilerplateModel.Item" />
<EntitySet Name="News" EntityType="boilerplateModel.News" />
<EntitySet Name="Settings" EntityType="boilerplateModel.Setting" />
<EntitySet Name="Users" EntityType="boilerplateModel.User" />
</EntityContainer>
<EntityType Name="Client">
<Key>
<PropertyRef Name="Client_Id" />
</Key>
<Property Name="Client_Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<Property Name="Client_Name" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="Client_LastName" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="Client_PhoneNumber" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="Client_UserName" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="Client_Email" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
</EntityType>
<EntityType Name="Item">
<Key>
<PropertyRef Name="Item_Id" />
</Key>
<Property Name="Item_Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<Property Name="Item_Title" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="Item_Type" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
</EntityType>
<EntityType Name="News">
<Key>
<PropertyRef Name="News_ID" />
</Key>
<Property Name="News_ID" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<Property Name="News_Title" Type="String" Nullable="false" MaxLength="100" FixedLength="false" Unicode="true" />
<Property Name="News_Description" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="News_Summary" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="News_Category" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="News_Tag" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="News_Date" Type="DateTime" Nullable="false" Precision="7" />
<Property Name="News_CreateDate" Type="DateTime" Nullable="false" Precision="7" />
<Property Name="News_EditDate" Type="DateTime" Precision="7" />
<Property Name="News_IMG" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
</EntityType>
<EntityType Name="Setting"> <EntityType Name="Setting">
<Key> <Key>
<PropertyRef Name="Setting_Id" /> <PropertyRef Name="Setting_Id" />
@ -94,76 +171,109 @@
<Property Name="User_Family" Type="String" MaxLength="150" FixedLength="false" Unicode="true" /> <Property Name="User_Family" Type="String" MaxLength="150" FixedLength="false" Unicode="true" />
<Property Name="User_Image" Type="String" MaxLength="50" FixedLength="false" Unicode="true" /> <Property Name="User_Image" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="User_NationalCode" Type="String" MaxLength="50" FixedLength="false" Unicode="true" /> <Property Name="User_NationalCode" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="User_Phone" Type="String" MaxLength="50" FixedLength="false" Unicode="true" Nullable="false" /> <Property Name="User_Phone" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="User_Password" Type="String" MaxLength="150" FixedLength="false" Unicode="true" /> <Property Name="User_Password" Type="String" MaxLength="150" FixedLength="false" Unicode="true" />
<Property Name="User_Code" Type="Int32" /> <Property Name="User_Code" Type="Int32" />
<Property Name="User_Token" Type="String" MaxLength="150" FixedLength="false" Unicode="true" /> <Property Name="User_Token" Type="String" MaxLength="150" FixedLength="false" Unicode="true" />
<Property Name="User_Status" Type="Int32" Nullable="false" /> <Property Name="User_Status" Type="Int32" Nullable="false" />
<Property Name="User_Role" Type="String" MaxLength="50" FixedLength="false" Unicode="true" Nullable="false" /> <Property Name="User_Role" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="User_Access" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" Nullable="false" /> <Property Name="User_Access" Type="String" Nullable="false" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="User_Email" Type="String" MaxLength="350" FixedLength="false" Unicode="true" /> <Property Name="User_Email" Type="String" MaxLength="350" FixedLength="false" Unicode="true" />
<Property Name="User_Birthday" Type="String" MaxLength="50" FixedLength="false" Unicode="true" /> <Property Name="User_Birthday" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="User_CreatedDate" Type="DateTime" Nullable="false" Precision="7" /> <Property Name="User_CreatedDate" Type="DateTime" Nullable="false" Precision="7" />
<Property Name="User_CreatedDateFa" Type="String" MaxLength="50" FixedLength="false" Unicode="true" Nullable="false" /> <Property Name="User_CreatedDateFa" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Name="User_LoginDate" Type="DateTime" Precision="7" /> <Property Name="User_LoginDate" Type="DateTime" Precision="7" />
<Property Name="User_LoginDateFa" Type="String" MaxLength="50" FixedLength="false" Unicode="true" /> <Property Name="User_LoginDateFa" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
</EntityType> </EntityType>
<EntityContainer Name="boilerplateEntities" annotation:LazyLoadingEnabled="true">
<EntitySet Name="Settings" EntityType="Self.Setting" />
<EntitySet Name="Users" EntityType="Self.User" />
</EntityContainer>
</Schema> </Schema>
</edmx:ConceptualModels> </edmx:ConceptualModels>
<!-- C-S mapping content --> <!-- C-S mapping content -->
<edmx:Mappings> <edmx:Mappings>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs"> <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
<EntityContainerMapping StorageEntityContainer="boilerplateModelStoreContainer" CdmEntityContainer="boilerplateEntities"> <EntityContainerMapping StorageEntityContainer="boilerplateModelStoreContainer" CdmEntityContainer="boilerplateEntities">
<EntitySetMapping Name="Clients">
<EntityTypeMapping TypeName="boilerplateModel.Client">
<MappingFragment StoreEntitySet="Client">
<ScalarProperty Name="Client_Email" ColumnName="Client_Email" />
<ScalarProperty Name="Client_UserName" ColumnName="Client_UserName" />
<ScalarProperty Name="Client_PhoneNumber" ColumnName="Client_PhoneNumber" />
<ScalarProperty Name="Client_LastName" ColumnName="Client_LastName" />
<ScalarProperty Name="Client_Name" ColumnName="Client_Name" />
<ScalarProperty Name="Client_Id" ColumnName="Client_Id" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Items">
<EntityTypeMapping TypeName="boilerplateModel.Item">
<MappingFragment StoreEntitySet="Item">
<ScalarProperty Name="Item_Type" ColumnName="Item_Type" />
<ScalarProperty Name="Item_Title" ColumnName="Item_Title" />
<ScalarProperty Name="Item_Id" ColumnName="Item_Id" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="News">
<EntityTypeMapping TypeName="boilerplateModel.News">
<MappingFragment StoreEntitySet="News">
<ScalarProperty Name="News_IMG" ColumnName="News_IMG" />
<ScalarProperty Name="News_EditDate" ColumnName="News_EditDate" />
<ScalarProperty Name="News_CreateDate" ColumnName="News_CreateDate" />
<ScalarProperty Name="News_Date" ColumnName="News_Date" />
<ScalarProperty Name="News_Tag" ColumnName="News_Tag" />
<ScalarProperty Name="News_Category" ColumnName="News_Category" />
<ScalarProperty Name="News_Summary" ColumnName="News_Summary" />
<ScalarProperty Name="News_Description" ColumnName="News_Description" />
<ScalarProperty Name="News_Title" ColumnName="News_Title" />
<ScalarProperty Name="News_ID" ColumnName="News_ID" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Settings"> <EntitySetMapping Name="Settings">
<EntityTypeMapping TypeName="boilerplateModel.Setting"> <EntityTypeMapping TypeName="boilerplateModel.Setting">
<MappingFragment StoreEntitySet="Setting"> <MappingFragment StoreEntitySet="Setting">
<ScalarProperty Name="Setting_Id" ColumnName="Setting_Id" />
<ScalarProperty Name="Setting_Name" ColumnName="Setting_Name" />
<ScalarProperty Name="Setting_Title" ColumnName="Setting_Title" />
<ScalarProperty Name="Setting_Discount" ColumnName="Setting_Discount" />
<ScalarProperty Name="Setting_Description" ColumnName="Setting_Description" />
<ScalarProperty Name="Setting_Keywords" ColumnName="Setting_Keywords" />
<ScalarProperty Name="Setting_Header" ColumnName="Setting_Header" />
<ScalarProperty Name="Setting_Footer" ColumnName="Setting_Footer" />
<ScalarProperty Name="Setting_Social" ColumnName="Setting_Social" />
<ScalarProperty Name="Setting_Username" ColumnName="Setting_Username" />
<ScalarProperty Name="Setting_Password" ColumnName="Setting_Password" />
<ScalarProperty Name="Setting_FromNumber" ColumnName="Setting_FromNumber" />
<ScalarProperty Name="Setting_Send" ColumnName="Setting_Send" />
<ScalarProperty Name="Setting_PaternLogin" ColumnName="Setting_PaternLogin" />
<ScalarProperty Name="Setting_Service" ColumnName="Setting_Service" />
<ScalarProperty Name="Setting_Address" ColumnName="Setting_Address" />
<ScalarProperty Name="Setting_PostCode" ColumnName="Setting_PostCode" />
<ScalarProperty Name="Setting_Phone" ColumnName="Setting_Phone" />
<ScalarProperty Name="Setting_Website" ColumnName="Setting_Website" /> <ScalarProperty Name="Setting_Website" ColumnName="Setting_Website" />
<ScalarProperty Name="Setting_Phone" ColumnName="Setting_Phone" />
<ScalarProperty Name="Setting_PostCode" ColumnName="Setting_PostCode" />
<ScalarProperty Name="Setting_Address" ColumnName="Setting_Address" />
<ScalarProperty Name="Setting_Service" ColumnName="Setting_Service" />
<ScalarProperty Name="Setting_PaternLogin" ColumnName="Setting_PaternLogin" />
<ScalarProperty Name="Setting_Send" ColumnName="Setting_Send" />
<ScalarProperty Name="Setting_FromNumber" ColumnName="Setting_FromNumber" />
<ScalarProperty Name="Setting_Password" ColumnName="Setting_Password" />
<ScalarProperty Name="Setting_Username" ColumnName="Setting_Username" />
<ScalarProperty Name="Setting_Social" ColumnName="Setting_Social" />
<ScalarProperty Name="Setting_Footer" ColumnName="Setting_Footer" />
<ScalarProperty Name="Setting_Header" ColumnName="Setting_Header" />
<ScalarProperty Name="Setting_Keywords" ColumnName="Setting_Keywords" />
<ScalarProperty Name="Setting_Description" ColumnName="Setting_Description" />
<ScalarProperty Name="Setting_Discount" ColumnName="Setting_Discount" />
<ScalarProperty Name="Setting_Title" ColumnName="Setting_Title" />
<ScalarProperty Name="Setting_Name" ColumnName="Setting_Name" />
<ScalarProperty Name="Setting_Id" ColumnName="Setting_Id" />
</MappingFragment> </MappingFragment>
</EntityTypeMapping> </EntityTypeMapping>
</EntitySetMapping> </EntitySetMapping>
<EntitySetMapping Name="Users"> <EntitySetMapping Name="Users">
<EntityTypeMapping TypeName="boilerplateModel.User"> <EntityTypeMapping TypeName="boilerplateModel.User">
<MappingFragment StoreEntitySet="User"> <MappingFragment StoreEntitySet="User">
<ScalarProperty Name="User_Id" ColumnName="User_Id" />
<ScalarProperty Name="User_Name" ColumnName="User_Name" />
<ScalarProperty Name="User_Family" ColumnName="User_Family" />
<ScalarProperty Name="User_Image" ColumnName="User_Image" />
<ScalarProperty Name="User_NationalCode" ColumnName="User_NationalCode" />
<ScalarProperty Name="User_Phone" ColumnName="User_Phone" />
<ScalarProperty Name="User_Password" ColumnName="User_Password" />
<ScalarProperty Name="User_Code" ColumnName="User_Code" />
<ScalarProperty Name="User_Token" ColumnName="User_Token" />
<ScalarProperty Name="User_Status" ColumnName="User_Status" />
<ScalarProperty Name="User_Role" ColumnName="User_Role" />
<ScalarProperty Name="User_Access" ColumnName="User_Access" />
<ScalarProperty Name="User_Email" ColumnName="User_Email" />
<ScalarProperty Name="User_Birthday" ColumnName="User_Birthday" />
<ScalarProperty Name="User_CreatedDate" ColumnName="User_CreatedDate" />
<ScalarProperty Name="User_CreatedDateFa" ColumnName="User_CreatedDateFa" />
<ScalarProperty Name="User_LoginDate" ColumnName="User_LoginDate" />
<ScalarProperty Name="User_LoginDateFa" ColumnName="User_LoginDateFa" /> <ScalarProperty Name="User_LoginDateFa" ColumnName="User_LoginDateFa" />
<ScalarProperty Name="User_LoginDate" ColumnName="User_LoginDate" />
<ScalarProperty Name="User_CreatedDateFa" ColumnName="User_CreatedDateFa" />
<ScalarProperty Name="User_CreatedDate" ColumnName="User_CreatedDate" />
<ScalarProperty Name="User_Birthday" ColumnName="User_Birthday" />
<ScalarProperty Name="User_Email" ColumnName="User_Email" />
<ScalarProperty Name="User_Access" ColumnName="User_Access" />
<ScalarProperty Name="User_Role" ColumnName="User_Role" />
<ScalarProperty Name="User_Status" ColumnName="User_Status" />
<ScalarProperty Name="User_Token" ColumnName="User_Token" />
<ScalarProperty Name="User_Code" ColumnName="User_Code" />
<ScalarProperty Name="User_Password" ColumnName="User_Password" />
<ScalarProperty Name="User_Phone" ColumnName="User_Phone" />
<ScalarProperty Name="User_NationalCode" ColumnName="User_NationalCode" />
<ScalarProperty Name="User_Image" ColumnName="User_Image" />
<ScalarProperty Name="User_Family" ColumnName="User_Family" />
<ScalarProperty Name="User_Name" ColumnName="User_Name" />
<ScalarProperty Name="User_Id" ColumnName="User_Id" />
</MappingFragment> </MappingFragment>
</EntityTypeMapping> </EntityTypeMapping>
</EntitySetMapping> </EntitySetMapping>

View File

@ -5,8 +5,11 @@
<!-- Diagram content (shape and connector positions) --> <!-- Diagram content (shape and connector positions) -->
<edmx:Diagrams> <edmx:Diagrams>
<Diagram DiagramId="da0c6095014e4dcdba4918743ea7998d" Name="Diagram1"> <Diagram DiagramId="da0c6095014e4dcdba4918743ea7998d" Name="Diagram1">
<EntityTypeShape EntityType="boilerplateModel.Setting" Width="1.5" PointX="0.75" PointY="0.75" IsExpanded="true" /> <EntityTypeShape EntityType="boilerplateModel.Client" Width="1.5" PointX="0.75" PointY="0.75" />
<EntityTypeShape EntityType="boilerplateModel.User" Width="1.5" PointX="2.75" PointY="0.75" IsExpanded="true" /> <EntityTypeShape EntityType="boilerplateModel.Item" Width="1.5" PointX="2.75" PointY="0.75" />
<EntityTypeShape EntityType="boilerplateModel.News" Width="1.5" PointX="8.75" PointY="0.75" />
<EntityTypeShape EntityType="boilerplateModel.Setting" Width="1.5" PointX="6.75" PointY="0.75" />
<EntityTypeShape EntityType="boilerplateModel.User" Width="1.5" PointX="4.75" PointY="0.75" />
</Diagram> </Diagram>
</edmx:Diagrams> </edmx:Diagrams>
</edmx:Designer> </edmx:Designer>

28
Models/News.cs Normal file
View File

@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace boilerplate.Models
{
using System;
using System.Collections.Generic;
public partial class News
{
public int News_ID { get; set; }
public string News_Title { get; set; }
public string News_Description { get; set; }
public string News_Summary { get; set; }
public string News_Category { get; set; }
public string News_Tag { get; set; }
public System.DateTime News_Date { get; set; }
public System.DateTime News_CreateDate { get; set; }
public Nullable<System.DateTime> News_EditDate { get; set; }
public string News_IMG { get; set; }
}
}

41
Models/NewsModel.cs Normal file
View File

@ -0,0 +1,41 @@
namespace boilerplate.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
// This is the metadata class where we define display names and validation rules.
public class NewsMetadata
{
[Display(Name = "عنوان خبر")]
[Required(ErrorMessage = "لطفاً عنوان خبر را وارد کنید.")]
public string News_Title { get; set; }
[Display(Name = "توضیحات کامل")]
[AllowHtml]
[Required(ErrorMessage = "لطفاً توضیحات خبر را وارد کنید.")]
public string News_Description { get; set; }
[Display(Name = "خلاصه خبر")]
public string News_Summary { get; set; }
[Display(Name = "دسته بندی")]
public string News_Category { get; set; }
[Display(Name = "تگ‌ها")]
public string News_Tag { get; set; }
[Display(Name = "تاریخ نمایش")]
public Nullable<System.DateTime> News_Date { get; set; }
[Display(Name = "تصویر شاخص")]
public string News_IMG { get; set; }
}
[MetadataType(typeof(NewsMetadata))]
public partial class News
{
// This part remains empty.
}
}

View File

@ -6,5 +6,7 @@
public string Message { get; set; } public string Message { get; set; }
public string Result { get; set; } public string Result { get; set; }
public string FileContent { get; set; } public string FileContent { get; set; }
public string RedirectUrl { get; set; } // این خط رو به کلاس اضافه کن
} }
} }

83
Views/Home/AllNews.cshtml Normal file
View File

@ -0,0 +1,83 @@
@model IEnumerable<boilerplate.Models.News>
@{
ViewBag.Title = "آخرین اخبار";
}
<style>
.badge-info {
color: black;
border: 1px solid lightgray;
}
body {
padding-top:0px !important;
}
</style>
<div class="container mt-5">
<h2 class="text-center mb-4">@ViewBag.Title</h2>
<hr />
<div class="row">
@if (!Model.Any())
{
<div class="col-12">
<p class="alert alert-warning text-center">در حال حاضر خبری برای نمایش وجود ندارد.</p>
</div>
}
else
{
foreach (var item in Model)
{
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm">
<img src="@Url.Content("~/Media/News/" + item.News_IMG)" class="card-img-top" alt="@item.News_Title" style="height: 200px; object-fit: cover;"
onerror="this.onerror=null;this.src='@Url.Content("~/Media/default-image.png")';">
<div class="card-body d-flex flex-column">
<h5 class="card-title">@item.News_Title</h5>
<p class="card-text text-muted">@item.News_Summary</p>
@* --- New section for Category and Tags --- *@
<div class="mt-3">
@if (!string.IsNullOrEmpty(item.News_Category))
{
<div class="mb-2">
<strong style="font-size: 0.9rem;">دسته بندی: </strong>
@* --- FIXED: Loop through categories to create separate badges --- *@
@{
var categories = item.News_Category.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var category in categories)
{
<span class="badge badge-info p-2 mr-1">@category.Trim()</span>
}
}
</div>
}
@if (!string.IsNullOrEmpty(item.News_Tag))
{
<div>
<strong style="font-size: 0.9rem;">تگ ها: </strong>
@{
var tags = item.News_Tag.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var tag in tags)
{
<span class="badge badge-light p-2 mr-1" style="color: #333; border: 1px solid #ccc;">@tag.Trim()</span>
}
}
</div>
}
</div>
@*<div class="mt-auto pt-3">
<a href="@Url.Action("NewsDetails", "Home", new { id = item.News_ID })" class="btn btn-primary">ادامه مطلب</a>
</div>*@
</div>
<div class="card-footer text-muted small">
@(item.News_Date > DateTime.MinValue ? new boilerplate.Models.Functions().ConvertToPersianDate(item.News_Date) : "")
</div>
</div>
</div>
}
}
</div>
</div>

116
Views/Panel/AddNews.cshtml Normal file
View File

@ -0,0 +1,116 @@
@model boilerplate.Controllers.PanelController.AddNewsViewModel
@{
ViewBag.Title = Model.News.News_ID == 0 ? "افزودن خبر جدید" : "ویرایش خبر";
Layout = "~/Views/_PanelSideBar.cshtml";
}
@section Heads {
<!-- Add CSS for Select2 library -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.ckeditor.com/4.16.2/standard/ckeditor.js"></script>
}
<div class="card card-custom">
<div class="card-header">
<h3 class="card-label">@ViewBag.Title</h3>
</div>
<div class="card-body">
@using (Html.BeginForm("AddNews", "Panel", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.News.News_ID)
@Html.HiddenFor(model => model.News.News_IMG)
if (!ViewData.ModelState.IsValid)
{
<div class="alert alert-danger">
@Html.ValidationSummary(false)
</div>
}
<div class="form-group">
<label>عنوان خبر</label>
@Html.EditorFor(model => model.News.News_Title, new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="form-group">
<label>دسته‌بندی‌ها</label>
<select name="selectedCategories" class="form-control select2-categories" multiple="multiple">
@{
var selectedCategories = (Model.News.News_Category ?? "").Split(',');
}
@foreach (var category in Model.AllCategories)
{
<option value="@category.Item_Title" @(selectedCategories.Contains(category.Item_Title) ? "selected" : "")>@category.Item_Title</option>
}
</select>
</div>
<div class="form-group">
<label>تگ‌ها</label>
<select name="selectedTags" class="form-control select2-tags" multiple="multiple">
@{
var selectedTags = (Model.News.News_Tag ?? "").Split(',');
}
@foreach (var tag in Model.AllTags)
{
<option value="@tag.Item_Title" @(selectedTags.Contains(tag.Item_Title) ? "selected" : "")>@tag.Item_Title</option>
}
</select>
</div>
<div class="form-group">
<label>خلاصه خبر</label>
@Html.TextAreaFor(model => model.News.News_Summary, new { @class = "form-control", rows = 3 })
</div>
<div class="form-group">
<label>توضیحات کامل</label>
@Html.TextAreaFor(model => model.News.News_Description, new { @class = "form-control", id = "newsDescriptionEditor" })
</div>
<div class="form-group">
<label>تصویر شاخص خبر</label>
<input type="file" name="imageFile" class="form-control-file" accept="image/*" />
@if (!string.IsNullOrEmpty(Model.News.News_IMG))
{
<div class="mt-2">
<span>تصویر فعلی:</span>
<img src="~/Media/News/@Model.News.News_IMG" style="width: 150px; height: auto;" />
</div>
}
</div>
<div class="card-footer text-right">
<button type="submit" class="btn btn-primary mr-2">ذخیره</button>
<a href="@Url.Action("NewsList", "Panel")" class="btn btn-secondary">انصراف</a>
</div>
}
</div>
</div>
@section Script {
<!-- کتابخانه Select2 (فرض بر این است که jQuery در لایوت اصلی شما لود شده است) -->
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function () {
// --- FIXED: Separate initialization for Categories and Tags ---
// Initialize Select2 for CATEGORIES (without the ability to add new ones)
$('.select2-categories').select2({
placeholder: "یک یا چند دسته بندی انتخاب کنید",
dir: "rtl"
});
// Initialize Select2 for TAGS (NOW also without the ability to add new ones)
$('.select2-tags').select2({
placeholder: "یک یا چند تگ انتخاب کنید",
dir: "rtl"
// The 'tags: true' option has been removed
});
// Initialize CKEditor
CKEDITOR.replace('newsDescriptionEditor', { language: 'fa' });
});
</script>
}

View File

@ -0,0 +1,300 @@
@model IEnumerable<boilerplate.Models.Client>
@{
ViewBag.Title = "مدیریت مشتریان";
Layout = "~/Views/_PanelSideBar.cshtml";
var currentUser = Session["User"] as boilerplate.Models.User;
}
<div class="card card-custom">
<div class="card-header">
<h3 class="card-title">@ViewBag.Title</h3>
<div class="card-toolbar">
<button type="button" class="btn btn-success font-weight-bolder mr-2" onclick="exportClients(event)">
<i class="fa fa-file-excel"></i>
خروجی اکسل
</button>
<button type="button" class="btn btn-primary font-weight-bolder" data-toggle="modal" data-target="#importModal">
<i class="fa fa-file-import"></i>
ورود از اکسل
</button>
</div>
</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th>نام</th>
<th>نام خانوادگی</th>
<th>شماره تلفن</th>
<th>نام کاربری</th>
<th>ایمیل</th>
<th>عملیات</th>
</tr>
</thead>
<tbody>
@foreach (var client in Model)
{
<tr id="client-row-@client.Client_Id">
<td data-prop="Client_Name">@client.Client_Name</td>
<td data-prop="Client_LastName">@client.Client_LastName</td>
<td data-prop="Client_PhoneNumber">@client.Client_PhoneNumber</td>
<td data-prop="Client_UserName">@client.Client_UserName</td>
<td data-prop="Client_Email">@client.Client_Email</td>
<td>
<button class="btn btn-sm btn-clean btn-icon" title="ویرایش" onclick="openEditModal(@client.Client_Id)">
<i class="fa fa-edit text-primary"></i>
</button>
<button class="btn btn-sm btn-clean btn-icon" title="حذف" onclick="deleteClient(@client.Client_Id)">
<i class="fa fa-trash text-danger"></i>
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<!-- Modal for Excel Upload -->
<div class="modal fade" id="importModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">ورود مشتریان از فایل اکسل</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>فایل اکسل خود را انتخاب کنید. ستون‌ها باید به ترتیب زیر باشند: نام، نام خانوادگی، شماره تلفن، نام کاربری، ایمیل.</p>
<input type="file" id="excelFileInput" class="form-control-file" accept=".xlsx" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">انصراف</button>
<button type="button" class="btn btn-primary" id="importButton" onclick="importClients(event)">بارگذاری</button>
</div>
</div>
</div>
</div>
<!-- *** ADDED: Modal for Editing a Client *** -->
<div class="modal fade" id="editClientModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">ویرایش اطلاعات مشتری</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editClientForm">
<input type="hidden" id="editClientId" />
<div class="form-group">
<label>نام</label>
<input type="text" id="editClientName" class="form-control" />
</div>
<div class="form-group">
<label>نام خانوادگی</label>
<input type="text" id="editClientLastName" class="form-control" />
</div>
<div class="form-group">
<label>شماره تلفن</label>
<input type="text" id="editClientPhone" class="form-control" />
</div>
<div class="form-group">
<label>نام کاربری</label>
<input type="text" id="editClientUsername" class="form-control" />
</div>
<div class="form-group">
<label>ایمیل</label>
<input type="email" id="editClientEmail" class="form-control" />
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">انصراف</button>
<button type="button" class="btn btn-primary" id="saveChangesBtn" onclick="saveChanges()">ذخیره تغییرات</button>
</div>
</div>
</div>
</div>
@section Script {
<script>
const authData = {
UserId: @(currentUser?.User_Id ?? 0),
Token: "@(currentUser?.User_Token ?? "")"
};
// *** FIXED: Re-added the full logic for importClients ***
function importClients(event) {
const fileInput = document.getElementById('excelFileInput');
if (fileInput.files.length === 0) {
toastr.error("لطفاً یک فایل اکسل انتخاب کنید.");
return;
}
const formData = new FormData();
formData.append("Auth", JSON.stringify(authData));
formData.append("ExcelFile", fileInput.files[0]);
const importBtn = event.target;
importBtn.disabled = true;
importBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> در حال بارگذاری...';
fetch('/api/Client/Import', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.Status === "Success") {
toastr.success(data.Message || "فایل با موفقیت بارگذاری شد.");
setTimeout(() => location.reload(), 2000);
} else {
toastr.error("خطا در بارگذاری فایل: " + (data.Message || data.Status));
}
})
.catch(error => {
toastr.error("خطا در برقراری ارتباط با سرور.");
})
.finally(() => {
importBtn.disabled = false;
importBtn.innerHTML = 'بارگذاری';
$('#importModal').modal('hide');
});
}
// *** FIXED: Re-added the full logic for exportClients ***
function exportClients(event) {
const exportBtn = event.target;
exportBtn.disabled = true;
exportBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> در حال آماده سازی...';
fetch('/api/Client/Export', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(authData)
})
.then(response => {
if (response.ok) return response.blob();
throw new Error('Network response was not ok.');
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = `Clients_${new Date().toISOString().slice(0, 10)}.xlsx`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
toastr.success("فایل اکسل آماده دانلود است.");
})
.catch(error => {
toastr.error("خطا در ساخت فایل اکسل.");
})
.finally(() => {
exportBtn.disabled = false;
exportBtn.innerHTML = '<i class="fa fa-file-excel"></i> خروجی اکسل';
});
}
// Function to open the edit modal and fetch client data
function openEditModal(clientId) {
fetch(`/api/Client/Get/${clientId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(authData)
})
.then(response => response.json())
.then(client => {
$('#editClientId').val(client.Client_Id);
$('#editClientName').val(client.Client_Name);
$('#editClientLastName').val(client.Client_LastName);
$('#editClientPhone').val(client.Client_PhoneNumber);
$('#editClientUsername').val(client.Client_UserName);
$('#editClientEmail').val(client.Client_Email);
$('#editClientModal').modal('show');
})
.catch(error => toastr.error("خطا در دریافت اطلاعات مشتری."));
}
// Function to save the changes from the edit modal
function saveChanges() {
const saveBtn = document.getElementById('saveChangesBtn');
saveBtn.disabled = true;
saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> در حال ذخیره...';
const clientData = {
Client_Id: parseInt($('#editClientId').val()),
Client_Name: $('#editClientName').val(),
Client_LastName: $('#editClientLastName').val(),
Client_PhoneNumber: $('#editClientPhone').val(),
Client_UserName: $('#editClientUsername').val(),
Client_Email: $('#editClientEmail').val()
};
const updateModel = {
Auth: authData,
Client: clientData
};
fetch('/api/Client/Update', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updateModel)
})
.then(response => response.json())
.then(data => {
if (data.Status === "Success") {
toastr.success("اطلاعات مشتری با موفقیت ویرایش شد.");
const row = $(`#client-row-${clientData.Client_Id}`);
row.find('[data-prop="Client_Name"]').text(clientData.Client_Name);
row.find('[data-prop="Client_LastName"]').text(clientData.Client_LastName);
row.find('[data-prop="Client_PhoneNumber"]').text(clientData.Client_PhoneNumber);
row.find('[data-prop="Client_UserName"]').text(clientData.Client_UserName);
row.find('[data-prop="Client_Email"]').text(clientData.Client_Email);
$('#editClientModal').modal('hide');
} else {
toastr.error("خطا در ویرایش: " + (data.Message || data.Status));
}
})
.catch(error => toastr.error("خطا در برقراری ارتباط با سرور."))
.finally(() => {
saveBtn.disabled = false;
saveBtn.innerHTML = 'ذخیره تغییرات';
});
}
// JavaScript function to delete a client
function deleteClient(clientId) {
if (!confirm("آیا از حذف این مشتری مطمئن هستید؟")) {
return;
}
const deleteAuthData = { ...authData, Id: clientId };
fetch('/api/Client/Delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(deleteAuthData)
})
.then(response => response.json())
.then(data => {
if (data.Status === "Success") {
toastr.success("مشتری با موفقیت حذف شد.");
$("#client-row-" + clientId).fadeOut(500, function() { $(this).remove(); });
} else {
toastr.error("خطا در حذف مشتری: " + (data.Message || data.Status));
}
})
.catch(error => {
toastr.error("خطا در برقراری ارتباط با سرور.");
});
}
</script>
}

View File

@ -70,22 +70,22 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-6 form-group"> @*<div class="col-lg-6 form-group">
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0"> <div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0" style="height:144px;">
<div class="card-body"> <div class="card-body">
<div class="d-flex align-items-center p-5"> <div class="d-flex align-items-center p-5">
<div class="mr-6"> <div class="mr-6">
<i class="fa fa-comments text-primary icon-3x"></i> <i class="fa fa-comments text-primary icon-3x"></i>
</div> </div>
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<a href="~/panel/Chats" class="text-gray text-hover-primary font-weight-bold font-size-h4 mb-3"> <a href="" class="text-gray text-hover-primary font-weight-bold font-size-h4 mb-3">
تالار گفتگو تالار گفتگو
</a> </a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>*@
@*<div class="col-lg-4 form-group"> @*<div class="col-lg-4 form-group">
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0"> <div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0">
<div class="card-body"> <div class="card-body">
@ -118,6 +118,21 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-6 form-group">
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0">
<div class="card-body" style="height:143px;">
<div class="d-flex align-items-center p-5">
<div class="mr-6">
<i class="fa fa-newspaper text-primary icon-3x"></i>
</div>
<div class="d-flex flex-column">
<a href="~/panel/NewsList" class="text-gray text-hover-primary font-weight-bold font-size-h4 mb-3">مدیریت اخبار</a>
</div>
</div>
</div>
</div>
</div>
</div> </div>
@ -128,4 +143,5 @@
</div> </div>
} }
@section Script{ @section Script{
} }

122
Views/Panel/Items.cshtml Normal file
View File

@ -0,0 +1,122 @@
@model IEnumerable<boilerplate.Models.Item>
@{
ViewBag.Title = ViewBag.PageTitle;
Layout = "~/Views/_PanelSideBar.cshtml";
var itemType = (int)ViewBag.ItemType;
}
<div class="row">
<!-- Add New Item Form -->
<div class="col-md-4">
<div class="card card-custom">
<div class="card-header">
<h3 class="card-title">افزودن آیتم جدید</h3>
</div>
<div class="card-body">
@using (Html.BeginForm("AddItem", "Panel", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.Hidden("Item_Type", itemType)
<div class="form-group">
<label>@ViewBag.NewItemLabel</label>
<input type="text" name="Item_Title" class="form-control" required />
</div>
<button type="submit" class="btn btn-primary">افزودن</button>
}
</div>
</div>
</div>
<!-- List of Existing Items -->
<div class="col-md-8">
<div class="card card-custom">
<div class="card-header">
<h3 class="card-title">@ViewBag.PageTitle</h3>
</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th>نام</th>
<th style="width: 120px;">عملیات</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr id="item-@item.Item_Id">
<td>
<span id="title-text-@item.Item_Id">@item.Item_Title</span>
<input type="text" id="title-input-@item.Item_Id" class="form-control d-none" value="@item.Item_Title" />
</td>
<td>
<button class="btn btn-sm btn-clean btn-icon" title="ویرایش" id="edit-btn-@item.Item_Id" onclick="editItem(@item.Item_Id)">
<i class="fa fa-edit text-primary"></i>
</button>
<button class="btn btn-sm btn-clean btn-icon d-none" title="ذخیره" id="save-btn-@item.Item_Id" onclick="saveItem(@item.Item_Id)">
<i class="fa fa-save text-success"></i>
</button>
<button class="btn btn-sm btn-clean btn-icon" title="حذف" onclick="deleteItem(@item.Item_Id)">
<i class="fa fa-trash text-danger"></i>
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
@section Script {
<script>
function editItem(id) {
// مخفی کردن متن و نمایش کادر ویرایش
$('#title-text-' + id).addClass('d-none');
$('#title-input-' + id).removeClass('d-none').focus();
// مخفی کردن دکمه ویرایش و نمایش دکمه ذخیره
$('#edit-btn-' + id).addClass('d-none');
$('#save-btn-' + id).removeClass('d-none');
}
function saveItem(id) {
var newTitle = $('#title-input-' + id).val();
if (!newTitle.trim()) {
toastr.error("نام نمی تواند خالی باشد.");
return;
}
$.post("@Url.Action("UpdateItem", "Panel")", { id: id, newTitle: newTitle }, function(data) {
if (data.success) {
// آپدیت متن و بازگشت به حالت نمایش
$('#title-text-' + id).text(newTitle).removeClass('d-none');
$('#title-input-' + id).addClass('d-none');
$('#edit-btn-' + id).removeClass('d-none');
$('#save-btn-' + id).addClass('d-none');
toastr.success("آیتم با موفقیت ویرایش شد.");
} else {
toastr.error("خطا در ویرایش: " + (data.message || ""));
}
}).fail(function() {
toastr.error("خطا در برقراری ارتباط با سرور.");
});
}
function deleteItem(id) {
if (confirm("آیا از حذف این آیتم مطمئن هستید؟")) {
$.post("@Url.Action("DeleteItem", "Panel")", { id: id }, function(data) {
if (data.success) {
$("#item-" + id).fadeOut();
toastr.success("آیتم با موفقیت حذف شد.");
} else {
toastr.error("خطا در حذف آیتم.");
}
});
}
}
</script>
}

View File

@ -128,7 +128,12 @@
toastr.success('ورود با موفقیت انجام شد !!!'); toastr.success('ورود با موفقیت انجام شد !!!');
setTimeout(function () { setTimeout(function () {
if (Return == '') { if (Return == '') {
if (data.role == 'Admin') {
location.href = "Index"; location.href = "Index";
}
else {
location.href = '@Url.Action("AllNews", "Home")';
}
} else { } else {
location.href = Return; location.href = Return;
} }
@ -150,7 +155,6 @@
}).always(function () { }).always(function () {
}); });
} else { } else {
toastr.error('کد تایید را وارد کنید.'); toastr.error('کد تایید را وارد کنید.');
} }
} }

View File

@ -0,0 +1,77 @@
@model IEnumerable<boilerplate.Models.News>
@{
ViewBag.Title = "لیست اخبار";
Layout = "~/Views/_PanelSideBar.cshtml";
}
<div class="card card-custom">
<div class="card-header">
<div class="card-title">
<h3 class="card-label">@ViewBag.Title</h3>
</div>
<div class="card-toolbar">
<a href="@Url.Action("AddNews", "Panel")" class="btn btn-primary font-weight-bolder">
<i class="fa fa-plus"></i>
افزودن خبر جدید
</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>تصویر</th>
<th>عنوان خبر</th>
<th>خلاصه</th>
<th>تاریخ ایجاد</th>
<th>عملیات</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr id="news-row-@item.News_ID">
<td>
<img src="~/Media/News/@item.News_IMG" alt="News Image" style="width: 100px; height: auto; border-radius: 8px;"
onerror="this.onerror=null;this.src='/Media/default-image.png';" />
</td>
<td>@item.News_Title</td>
<td>@item.News_Summary</td>
<td>
@(item.News_CreateDate > DateTime.MinValue ? new boilerplate.Models.Functions().ConvertToPersianDate(item.News_CreateDate) : "")
</td>
<td>
<a href="@Url.Action("AddNews", "Panel", new { id = item.News_ID })" class="btn btn-sm btn-clean btn-icon" title="ویرایش">
<i class="fa fa-edit text-primary"></i>
</a>
<button class="btn btn-sm btn-clean btn-icon" title="حذف" onclick="deleteNews(@item.News_ID)">
<i class="fa fa-trash text-danger"></i>
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
@section Script {
<script>
function deleteNews(id) {
if (confirm("آیا از حذف این خبر مطمئن هستید؟ این عملیات قابل بازگشت نیست.")) {
$.post("@Url.Action("DeleteNews", "Panel")", { id: id }, function(data) {
if (data.success) {
$("#news-row-" + id).fadeOut(500, function() { $(this).remove(); });
toastr.success("خبر با موفقیت حذف شد.");
} else {
toastr.error("خطا در حذف خبر. " + (data.message || ""));
}
}).fail(function() {
toastr.error("خطا در برقراری ارتباط با سرور.");
});
}
}
</script>
}

View File

@ -6,7 +6,6 @@
ViewBag.Title = Model.User_Id == 0 ? "کاربر جدید" : Model.User_Name + " " + Model.User_Family; ViewBag.Title = Model.User_Id == 0 ? "کاربر جدید" : Model.User_Name + " " + Model.User_Family;
Layout = "~/Views/_PanelSideBar.cshtml"; Layout = "~/Views/_PanelSideBar.cshtml";
Functions functions = new Functions(); Functions functions = new Functions();
} }
<form autocomplete="off"> <form autocomplete="off">
<div class="row"> <div class="row">
@ -165,6 +164,13 @@
تنظیمات تنظیمات
</label> </label>
</div> </div>
<div class="checkbox-list mb-3">
<label class="checkbox">
<input type="checkbox" name="chkAccess" value="ManageItems" @(Model.User_Access != null && Model.User_Access.Contains("ManageItems") ? "checked" : "") />
<span></span>
مدیریت دسته‌بندی و تگ
</label>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -219,6 +225,14 @@
}); });
function Save() { function Save() {
// --- ADDED: Client-side validation for image on new users ---
var isNew = (Id === 0);
var fileInput = $("#fuImage")[0];
if (isNew && fileInput.files.length === 0) {
toastr.error("لطفاً یک تصویر برای کاربر انتخاب کنید.");
return; // Stop the function if image is missing
}
let Phone = $("#txtPhone").val().trim(); let Phone = $("#txtPhone").val().trim();
if (Phone.length) { if (Phone.length) {
let Access = ""; let Access = "";
@ -238,7 +252,7 @@
$("#btnSave").css("opacity", 0.5); $("#btnSave").css("opacity", 0.5);
$("#btnSave").attr("onclick", ""); $("#btnSave").attr("onclick", "");
let model = { let model = {
Auth: { UserId: UserId, Token: Token }, Auth: { UserId: @User.User_Id, Token: "@User.User_Token" },
Id: Id, Id: Id,
Name: $("#txtName").val().trim(), Name: $("#txtName").val().trim(),
Family: $("#txtFamily").val().trim(), Family: $("#txtFamily").val().trim(),
@ -255,12 +269,18 @@
ajax.addEventListener("load", function (event) { ajax.addEventListener("load", function (event) {
$("#btnSave").css("opacity", 1); $("#btnSave").css("opacity", 1);
let data = JSON.parse(event.target.responseText); let data = JSON.parse(event.target.responseText);
if (data.Status == "Success") { if (data.Status == "Success") {
toastr.success("ذخیره سازی با موفقیت انجام شد"); toastr.success("ذخیره سازی با موفقیت انجام شد");
setTimeout(function () { setTimeout(function () {
location.href = `../Panel/User/${data.Result}`; location.href = `../Panel/User/${data.Result}`;
}, 1500); }, 1500);
} else { }
else if (data.Status == "DuplicatePhone") {
$("#btnSave").attr("onclick", "Save()"); // Re-enable button
toastr.error("این شماره تلفن قبلاً در سیستم ثبت شده است!");
}
else {
$("#btnSave").attr("onclick", "Save()"); $("#btnSave").attr("onclick", "Save()");
console.log(data); console.log(data);
toastr.warning("خطا هنگام ذخیره سازی اطلاعات"); toastr.warning("خطا هنگام ذخیره سازی اطلاعات");
@ -291,7 +311,7 @@
confirmButtonText: 'بله' confirmButtonText: 'بله'
}).then((result) => { }).then((result) => {
if (result.value) { if (result.value) {
$.post("../api/User/Delete", { Id: Id, UserId: UserId, Token: Token }).done(function (data) { $.post("../api/User/Delete", { Id: Id, UserId: @User.User_Id, Token: "@User.User_Token" }).done(function (data) {
if (data.Status == "Success") { if (data.Status == "Success") {
$(".btns").remove(); $(".btns").remove();
toastr.success("حذف با موفقیت انجام شد"); toastr.success("حذف با موفقیت انجام شد");

View File

@ -9,7 +9,7 @@
</head> </head>
<body> <body>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark"> @*<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark">
<div class="container"> <div class="container">
@Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" }) @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" title="Toggle navigation" aria-controls="navbarSupportedContent" <button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" title="Toggle navigation" aria-controls="navbarSupportedContent"
@ -22,7 +22,7 @@
<li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, new { @class = "nav-link" })</li> <li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, new { @class = "nav-link" })</li>
</ul> </ul>
</div> </div>
</div> </div>*@
</nav> </nav>
<div class="container body-content"> <div class="container body-content">
@RenderBody() @RenderBody()

View File

@ -8,6 +8,17 @@
</sectionGroup> </sectionGroup>
</configSections> </configSections>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.6.1.0" newVersion="4.6.1.0" />
</dependentAssembly>
<!-- ممکن است dependentAssembly های دیگری هم اینجا داشته باشید -->
</assemblyBinding>
</runtime>
<system.web.webPages.razor> <system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage"> <pages pageBaseType="System.Web.Mvc.WebViewPage">

View File

@ -4,6 +4,7 @@
var User = Session["User"] as User; var User = Session["User"] as User;
if (User == null) { return; } if (User == null) { return; }
bool HasAccess(string Access) => new Functions().HasAccess(User.User_Access, Access); bool HasAccess(string Access) => new Functions().HasAccess(User.User_Access, Access);
} }
@section Heads { @section Heads {
@RenderSection("Heads", false) @RenderSection("Heads", false)
@ -81,7 +82,7 @@
<span></span> <span></span>
</button> </button>
<a href="~/Panel"> <a href="~/Panel">
<img class="w-50" src="~/Media/Logo.png" /> <img class="w-50" src="~/Media/User.png" />
</a> </a>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<button class="btn p-0 burger-icon ml-4 d-none d-md-block" id="kt_header_mobile_toggle"> <button class="btn p-0 burger-icon ml-4 d-none d-md-block" id="kt_header_mobile_toggle">
@ -115,7 +116,7 @@
<div class="aside aside-left aside-fixed d-flex flex-column flex-row-auto" id="kt_aside"> <div class="aside aside-left aside-fixed d-flex flex-column flex-row-auto" id="kt_aside">
<div class="brand flex-column-auto d-flex" id="kt_brand"> <div class="brand flex-column-auto d-flex" id="kt_brand">
<a href="~/Panel"> <a href="~/Panel">
<img class="w-75" src="~/Media/Logo.png" /> <img class="" src="~/Media/User.png" style="width:30%;"/>
</a> </a>
<button class="brand-toggle btn btn-sm px-0 d-none d-md-inline-block" id="kt_aside_toggle"> <button class="brand-toggle btn btn-sm px-0 d-none d-md-inline-block" id="kt_aside_toggle">
<span class="svg-icon svg-icon svg-icon-xl"> <span class="svg-icon svg-icon svg-icon-xl">
@ -179,6 +180,69 @@
</li> </li>
} }
@if (HasAccess("ManageNews"))
{
<li class="menu-item menu-item-submenu" aria-haspopup="true" data-menu-toggle="hover" id="NewsMenu">
<a href="javascript:;" class="menu-link menu-toggle">
<i class="menu-icon fa fa-newspaper"></i>
<span class="menu-text">مدیریت اخبار</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item" aria-haspopup="true" id="NewsListMenu">
<a href="~/panel/NewsList" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">لیست اخبار</span>
</a>
</li>
</ul>
</div>
</li>
}
@if (HasAccess("ManageItems"))
{
<li class="menu-item menu-item-submenu" aria-haspopup="true" data-menu-toggle="hover" id="ItemsMenu">
<a href="javascript:;" class="menu-link menu-toggle">
<i class="menu-icon fa fa-tags"></i>
<span class="menu-text">دسته‌بندی و تگ</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item" aria-haspopup="true" id="CategoriesMenu">
<a href="~/panel/Items/1" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">مدیریت دسته‌بندی</span>
</a>
</li>
<li class="menu-item" aria-haspopup="true" id="TagsMenu">
<a href="~/panel/Items/2" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">مدیریت تگ‌ها</span>
</a>
</li>
</ul>
</div>
</li>
}
@if (HasAccess("SomeAccess"))
{
<li class="menu-item" aria-haspopup="true" id="ClientsMenu">
<a href="~/panel/ClientManagement" class="menu-link">
<i class="menu-icon fa fa-users"></i>
<span class="menu-text">مدیریت مشتریان</span>
</a>
</li>
}
@if (HasAccess("ManageSettings")) @if (HasAccess("ManageSettings"))
{ {
<li class="menu-item" aria-haspopup="true" id="SettingMenu"> <li class="menu-item" aria-haspopup="true" id="SettingMenu">

View File

@ -66,6 +66,22 @@
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" /> <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.9.0" newVersion="5.2.9.0" /> <bindingRedirect oldVersion="1.0.0.0-5.2.9.0" newVersion="5.2.9.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.6.0" newVersion="4.1.6.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
<system.codedom> <system.codedom>

View File

@ -45,20 +45,72 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="ClosedXML, Version=0.105.0.0, Culture=neutral, PublicKeyToken=fd1eb21b62ae805b, processorArchitecture=MSIL">
<HintPath>packages\ClosedXML.0.105.0\lib\netstandard2.0\ClosedXML.dll</HintPath>
</Reference>
<Reference Include="ClosedXML.Parser, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d5f7376574c51ec, processorArchitecture=MSIL">
<HintPath>packages\ClosedXML.Parser.2.0.0\lib\netstandard2.0\ClosedXML.Parser.dll</HintPath>
</Reference>
<Reference Include="DocumentFormat.OpenXml, Version=3.1.1.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17, processorArchitecture=MSIL">
<HintPath>packages\DocumentFormat.OpenXml.3.1.1\lib\net46\DocumentFormat.OpenXml.dll</HintPath>
</Reference>
<Reference Include="DocumentFormat.OpenXml.Framework, Version=3.1.1.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17, processorArchitecture=MSIL">
<HintPath>packages\DocumentFormat.OpenXml.Framework.3.1.1\lib\net46\DocumentFormat.OpenXml.Framework.dll</HintPath>
</Reference>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath> <HintPath>packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
</Reference> </Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath> <HintPath>packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference> </Reference>
<Reference Include="ExcelNumberFormat, Version=1.1.0.0, Culture=neutral, PublicKeyToken=23c6f5d73be07eca, processorArchitecture=MSIL">
<HintPath>packages\ExcelNumberFormat.1.1.0\lib\net20\ExcelNumberFormat.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.HashCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="RestSharp"> <Reference Include="RBush, Version=4.0.0.0, Culture=neutral, PublicKeyToken=c77e27b81f4d0187, processorArchitecture=MSIL">
<HintPath>..\..\..\..\..\repo\AloCmsShopNew\bin\RestSharp.dll</HintPath> <HintPath>packages\RBush.Signed.4.0.0\lib\net47\RBush.dll</HintPath>
</Reference>
<Reference Include="RestSharp, Version=112.1.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
<HintPath>packages\RestSharp.112.1.0\lib\net48\RestSharp.dll</HintPath>
</Reference>
<Reference Include="SixLabors.Fonts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13, processorArchitecture=MSIL">
<HintPath>packages\SixLabors.Fonts.1.0.0\lib\netstandard2.0\SixLabors.Fonts.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Security" /> <Reference Include="System.Security" />
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=8.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Text.Json.8.0.4\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web.Entity" /> <Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" /> <Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.ComponentModel.DataAnnotations" />
@ -126,6 +178,7 @@
<Private>True</Private> <Private>True</Private>
<HintPath>packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll</HintPath> <HintPath>packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll</HintPath>
</Reference> </Reference>
<Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"> <Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform">
@ -172,7 +225,14 @@
<Compile Include="Global.asax.cs"> <Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon> <DependentUpon>Global.asax</DependentUpon>
</Compile> </Compile>
<Compile Include="Models\Client.cs">
<DependentUpon>Model1.tt</DependentUpon>
</Compile>
<Compile Include="Models\NewsModel.cs" />
<Compile Include="Models\Functions.cs" /> <Compile Include="Models\Functions.cs" />
<Compile Include="Models\Item.cs">
<DependentUpon>Model1.tt</DependentUpon>
</Compile>
<Compile Include="Models\Model1.Context.cs"> <Compile Include="Models\Model1.Context.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@ -188,6 +248,9 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>Model1.edmx</DependentUpon> <DependentUpon>Model1.edmx</DependentUpon>
</Compile> </Compile>
<Compile Include="Models\News.cs">
<DependentUpon>Model1.tt</DependentUpon>
</Compile>
<Compile Include="Models\Setting.cs"> <Compile Include="Models\Setting.cs">
<DependentUpon>Model1.tt</DependentUpon> <DependentUpon>Model1.tt</DependentUpon>
</Compile> </Compile>
@ -3497,6 +3560,11 @@
<Content Include="Views\Panel\Users.cshtml" /> <Content Include="Views\Panel\Users.cshtml" />
<Content Include="Views\Panel\User.cshtml" /> <Content Include="Views\Panel\User.cshtml" />
<Content Include="Views\Panel\Login.cshtml" /> <Content Include="Views\Panel\Login.cshtml" />
<Content Include="Views\Home\AllNews.cshtml" />
<Content Include="Views\Panel\NewsList.cshtml" />
<Content Include="Views\Panel\AddNews.cshtml" />
<Content Include="Views\Panel\Items.cshtml" />
<Content Include="Views\Panel\ClientManagement.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="App_Data\" /> <Folder Include="App_Data\" />

View File

@ -2,7 +2,12 @@
<packages> <packages>
<package id="Antlr" version="3.5.0.2" targetFramework="net48" /> <package id="Antlr" version="3.5.0.2" targetFramework="net48" />
<package id="bootstrap" version="5.2.3" targetFramework="net48" /> <package id="bootstrap" version="5.2.3" targetFramework="net48" />
<package id="ClosedXML" version="0.105.0" targetFramework="net48" />
<package id="ClosedXML.Parser" version="2.0.0" targetFramework="net48" />
<package id="DocumentFormat.OpenXml" version="3.1.1" targetFramework="net48" />
<package id="DocumentFormat.OpenXml.Framework" version="3.1.1" targetFramework="net48" />
<package id="EntityFramework" version="6.2.0" targetFramework="net48" /> <package id="EntityFramework" version="6.2.0" targetFramework="net48" />
<package id="ExcelNumberFormat" version="1.1.0" targetFramework="net48" />
<package id="jQuery" version="3.7.0" targetFramework="net48" /> <package id="jQuery" version="3.7.0" targetFramework="net48" />
<package id="Microsoft.AspNet.Mvc" version="5.2.9" targetFramework="net48" /> <package id="Microsoft.AspNet.Mvc" version="5.2.9" targetFramework="net48" />
<package id="Microsoft.AspNet.Razor" version="3.2.9" targetFramework="net48" /> <package id="Microsoft.AspNet.Razor" version="3.2.9" targetFramework="net48" />
@ -13,9 +18,23 @@
<package id="Microsoft.AspNet.WebApi.HelpPage" version="5.2.9" targetFramework="net48" /> <package id="Microsoft.AspNet.WebApi.HelpPage" version="5.2.9" targetFramework="net48" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.9" targetFramework="net48" /> <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.9" targetFramework="net48" />
<package id="Microsoft.AspNet.WebPages" version="3.2.9" targetFramework="net48" /> <package id="Microsoft.AspNet.WebPages" version="3.2.9" targetFramework="net48" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
<package id="Microsoft.Bcl.HashCode" version="1.1.1" targetFramework="net48" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.1" targetFramework="net48" /> <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.1" targetFramework="net48" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
<package id="Microsoft.Web.Infrastructure" version="2.0.0" targetFramework="net48" /> <package id="Microsoft.Web.Infrastructure" version="2.0.0" targetFramework="net48" />
<package id="Modernizr" version="2.8.3" targetFramework="net48" /> <package id="Modernizr" version="2.8.3" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" /> <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
<package id="RBush.Signed" version="4.0.0" targetFramework="net48" />
<package id="RestSharp" version="112.1.0" targetFramework="net48" />
<package id="SixLabors.Fonts" version="1.0.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Memory" version="4.5.5" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.6.1" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net48" />
<package id="System.Text.Json" version="8.0.4" targetFramework="net48" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
<package id="WebGrease" version="1.6.0" targetFramework="net48" /> <package id="WebGrease" version="1.6.0" targetFramework="net48" />
</packages> </packages>