├── Web ├── AYN.Web │ ├── wwwroot │ │ ├── js │ │ │ ├── site.min.js │ │ │ ├── site.js │ │ │ ├── demo.js │ │ │ └── sequence-theme.modern-slide-in.js │ │ ├── favicon.ico │ │ ├── images.jpg │ │ ├── scss │ │ │ ├── custom │ │ │ │ ├── mixins │ │ │ │ │ ├── _typography.scss │ │ │ │ │ ├── _animations.scss │ │ │ │ │ ├── _misc.scss │ │ │ │ │ ├── _navigation.scss │ │ │ │ │ └── _base.scss │ │ │ │ ├── _mixins.scss │ │ │ │ ├── _progress-bars.scss │ │ │ │ ├── _alerts.scss │ │ │ │ ├── _tables.scss │ │ │ │ ├── _modals.scss │ │ │ │ ├── _misc.scss │ │ │ │ ├── _background.scss │ │ │ │ ├── _footers.scss │ │ │ │ ├── _badges.scss │ │ │ │ ├── _cards.scss │ │ │ │ ├── _dropdown.scss │ │ │ │ ├── _navbars.scss │ │ │ │ ├── _pagination.scss │ │ │ │ ├── _tooltips.scss │ │ │ │ ├── _typography.scss │ │ │ │ └── _popovers.scss │ │ │ ├── base │ │ │ │ ├── _base.scss │ │ │ │ └── _variables.scss │ │ │ ├── modules │ │ │ │ └── _typography.scss │ │ │ ├── lazy.scss │ │ │ └── style.scss │ │ ├── img │ │ │ ├── reacts │ │ │ │ ├── care.gif │ │ │ │ ├── haha.gif │ │ │ │ ├── like.gif │ │ │ │ ├── love.gif │ │ │ │ ├── sad.gif │ │ │ │ ├── wow.gif │ │ │ │ └── angry.gif │ │ │ └── upload-file-image.png │ │ ├── fonts │ │ │ ├── linea │ │ │ │ ├── linea-basic-10.eot │ │ │ │ ├── linea-basic-10.ttf │ │ │ │ └── linea-basic-10.woff │ │ │ └── outline │ │ │ │ ├── untitled-font-5.eot │ │ │ │ ├── untitled-font-5.ttf │ │ │ │ └── untitled-font-5.woff │ │ └── lib │ │ │ └── tinymce │ │ │ ├── plugins │ │ │ ├── emoticons │ │ │ │ └── index.min.js │ │ │ ├── hr │ │ │ │ └── plugin.min.js │ │ │ └── code │ │ │ │ └── plugin.min.js │ │ │ └── skins │ │ │ └── content │ │ │ └── default │ │ │ └── content.min.css │ ├── Views │ │ ├── _ViewStart.cshtml │ │ ├── _ViewImports.cshtml │ │ ├── Shared │ │ │ ├── _GetAllPostsPartial.cshtml │ │ │ ├── _ValidationScriptsPartial.cshtml │ │ │ ├── _SearchBarPartial.cshtml │ │ │ ├── _DeleteConfirmationPartial.cshtml │ │ │ ├── _AlphabetFilterPartial.cshtml │ │ │ ├── Components │ │ │ │ ├── GetRecentAds │ │ │ │ │ └── Default.cshtml │ │ │ │ ├── GetRecentlyPromotedAds │ │ │ │ │ └── Default.cshtml │ │ │ │ ├── GetHomePageStatistics │ │ │ │ │ └── Default.cshtml │ │ │ │ ├── GetSuggestionPeople │ │ │ │ │ └── Default.cshtml │ │ │ │ ├── GetMoreAdsFromUser │ │ │ │ │ └── Default.cshtml │ │ │ │ └── GetUserRecentAdViews │ │ │ │ │ └── Default.cshtml │ │ │ ├── Error.cshtml │ │ │ └── _CookieConsentPartial.cshtml │ │ ├── Home │ │ │ └── Privacy.cshtml │ │ ├── Chat │ │ │ └── All.cshtml │ │ ├── Users │ │ │ ├── Followers.cshtml │ │ │ └── Followees.cshtml │ │ ├── Comments │ │ │ └── Edit.cshtml │ │ └── Posts │ │ │ └── Edit.cshtml │ ├── Areas │ │ ├── Administration │ │ │ ├── Views │ │ │ │ ├── _ViewStart.cshtml │ │ │ │ ├── Categories │ │ │ │ │ ├── ListSubCategories.cshtml │ │ │ │ │ ├── AddSubCategory.cshtml │ │ │ │ │ └── Edit.cshtml │ │ │ │ ├── _ViewImports.cshtml │ │ │ │ ├── Chat │ │ │ │ │ └── BlacklistedWords.cshtml │ │ │ │ ├── Emojis │ │ │ │ │ ├── All.cshtml │ │ │ │ │ └── Create.cshtml │ │ │ │ ├── Users │ │ │ │ │ └── Ban.cshtml │ │ │ │ ├── Ads │ │ │ │ │ └── Promote.cshtml │ │ │ │ └── SubCategories │ │ │ │ │ └── Edit.cshtml │ │ │ └── Controllers │ │ │ │ ├── AdministrationController.cs │ │ │ │ ├── ChatController.cs │ │ │ │ └── EmojisController.cs │ │ └── Identity │ │ │ ├── Pages │ │ │ ├── Account │ │ │ │ ├── _ViewImports.cshtml │ │ │ │ ├── Manage │ │ │ │ │ ├── _ViewImports.cshtml │ │ │ │ │ └── _ManageNav.cshtml │ │ │ │ ├── ConfirmEmail.cshtml │ │ │ │ ├── ConfirmEmailChange.cshtml │ │ │ │ ├── RegisterConfirmation.cshtml │ │ │ │ ├── ForgotPasswordConfirmation.cshtml │ │ │ │ ├── ForgotPasswordConfirmation.cshtml.cs │ │ │ │ └── ForgotPassword.cshtml │ │ │ ├── _ViewStart.cshtml │ │ │ ├── _ViewImports.cshtml │ │ │ └── _ValidationScriptsPartial.cshtml │ │ │ └── IdentityHostingStartup.cs │ ├── Validators │ │ └── IValidator.cs │ ├── appsettings.Development.json │ ├── Controllers │ │ ├── BaseController.cs │ │ ├── CategoriesController.cs │ │ ├── HomeController.cs │ │ ├── TownsController.cs │ │ ├── ReportsController.cs │ │ └── PostReactsController.cs │ ├── Program.cs │ ├── bundleconfig.json │ ├── Infrastructure │ │ └── Extensions │ │ │ └── ClaimsPrincipalExtensions.cs │ ├── Properties │ │ └── launchSettings.json │ ├── ViewComponents │ │ ├── GetRecentAdsViewComponent.cs │ │ ├── GetRecentlyPromotedAdsViewComponent.cs │ │ ├── GetUserAllAdsViewComponent.cs │ │ ├── GetUserRecentAdsViewComponent.cs │ │ ├── GetSuggestionPeopleViewComponent.cs │ │ ├── GetUserRecentAdViewsViewComponent.cs │ │ ├── GetHomePageStatisticsViewComponent.cs │ │ ├── GetMoreAdsFromUserViewComponent.cs │ │ └── GetUserPostsViewComponent.cs │ └── appsettings.json └── AYN.Web.ViewModels │ ├── Home │ ├── IndexViewModel.cs │ └── IndexPageStatisticsViewModel.cs │ ├── Comments │ ├── CreateCommentInputModel.cs │ ├── EditCommentInputModel.cs │ └── CommentViewModel.cs │ ├── PostReacts │ ├── PostReactResponseModel.cs │ └── PostReactInputModel.cs │ ├── Payments │ └── PaymentViewModel.cs │ ├── Ads │ ├── ListAdsViewModel.cs │ ├── ListMoreAdsByUserViewModel.cs │ ├── ListGetFromSearchViewModel.cs │ ├── ListAllAdsViewModel.cs │ ├── GetAdViewModel.cs │ ├── GetAdsViewModel.cs │ ├── MoreAdsByUserViewModel.cs │ └── WishlistAdsViewModel.cs │ ├── ErrorViewModel.cs │ ├── Notifications │ ├── CreateNotificationInputModel.cs │ ├── ListAllNotificationsViewModel.cs │ └── GetAllNotificationsForUserViewModel.cs │ ├── Administration │ ├── Emojis │ │ ├── ListEmojiViewModel.cs │ │ ├── CreateEmojiInputModel.cs │ │ └── EmojiViewModel.cs │ ├── Ads │ │ ├── ListAllAdsViewModel.cs │ │ ├── PromoteAdInputModel.cs │ │ └── GetAllAdsViewModel.cs │ ├── Users │ │ ├── ListAllUserViewModel.cs │ │ ├── BanUserInputModel.cs │ │ └── GetAllUsersViewModel.cs │ ├── Reports │ │ ├── ListAllReportsViewModel.cs │ │ └── GetAllReportsViewModel.cs │ ├── Chat │ │ ├── ListBlacklistWordsViewModel.cs │ │ └── BlacklistWordViewModel.cs │ ├── Categories │ │ ├── ListAllCategoriesViewModel.cs │ │ ├── AddSubCategoryInputModel.cs │ │ ├── EditCategoryInputModel.cs │ │ ├── GetAllCategoriesViewModel.cs │ │ └── CreateCategoryInputModel.cs │ ├── SubCategories │ │ ├── SubCategoryViewModel.cs │ │ └── EditSubCategoryInputModel.cs │ └── Panels │ │ └── IndexViewModel.cs │ ├── Users │ ├── ListFolloweesViewModel.cs │ ├── ListFollowersViewModel.cs │ ├── ListSuggestionPeopleViewModel.cs │ ├── ListUserAdsViewModel.cs │ ├── UserWishlistViewModel.cs │ ├── EditUserViewModel.cs │ ├── GetFollowersViewModel.cs │ ├── FolloweeViewModel.cs │ ├── FollowerViewModel.cs │ ├── GetSuggestionPeopleViewModel.cs │ └── GetUserProfileBaseDetailsViewModel.cs │ ├── Chat │ ├── ListChatConversationsViewModel.cs │ ├── ChatUserViewModel.cs │ ├── ChatWithUserViewModel.cs │ ├── ChatSendMessageInputModel.cs │ ├── ChatConversationsViewModel.cs │ └── ChatMessagesWithUserViewModel.cs │ ├── Posts │ ├── ListUserPostsViewModel.cs │ ├── CreatePostInputModel.cs │ ├── EditPostInputModel.cs │ └── GetUserPostsViewModel.cs │ ├── Addresses │ └── GetAddressesViewModel.cs │ ├── Categories │ ├── CategoryViewModel.cs │ └── ListAllCategoriesViewModel.cs │ ├── SubCategories │ ├── CreateSubCategoryInputModel.cs │ └── SubCategoryViewModel.cs │ ├── Reports │ └── CreateReportInputModel.cs │ ├── Feedback │ └── CreateFeedbackInputModel.cs │ ├── PagingViewModel.cs │ └── AYN.Web.ViewModels.csproj ├── .editorconfig ├── Services ├── AYN.Services.Mapping │ ├── IMapTo.cs │ ├── IMapFrom.cs │ ├── IHaveCustomMappings.cs │ ├── AYN.Services.Mapping.csproj │ └── QueryableMappingExtensions.cs ├── AYN.Services.Data │ ├── Interfaces │ │ ├── IUserAdsViewsService.cs │ │ ├── ICloudinaryService.cs │ │ ├── IFeedbackService.cs │ │ ├── IPostReactsService.cs │ │ ├── IUserLatestAdViewsService.cs │ │ ├── IAddressesService.cs │ │ ├── IWordsBlacklistService.cs │ │ ├── INotificationsService.cs │ │ ├── ITownsService.cs │ │ ├── IEmojisService.cs │ │ ├── IWishlistsService.cs │ │ ├── IReportsService.cs │ │ ├── ICommentsService.cs │ │ ├── IPostsService.cs │ │ ├── IMessagesService.cs │ │ ├── ISubCategoriesService.cs │ │ ├── ICategoriesService.cs │ │ ├── IUsersService.cs │ │ └── IAdsService.cs │ ├── Implementations │ │ ├── FeedbackService.cs │ │ ├── UserLatestAdViewsService.cs │ │ └── UserAdsViewsService.cs │ └── AYN.Services.Data.csproj ├── AYN.Services.Messaging │ ├── EmailAttachment.cs │ ├── IEmailSender.cs │ ├── NullMessageSender.cs │ └── AYN.Services.Messaging.csproj ├── AYN.Services.RecurringJobs │ ├── AYN.Services.RecurringJobs.csproj │ └── UnpromoteExpiredAdsRecurringJob.cs └── AYN.Services │ └── AYN.Services.csproj ├── Data ├── AYN.Data.Models │ ├── Enumerations │ │ ├── CommentVoteValue.cs │ │ ├── Gender.cs │ │ ├── AdType.cs │ │ ├── DeliveryTake.cs │ │ ├── ProductCondition.cs │ │ ├── ReactionType.cs │ │ └── ReportType.cs │ ├── Emoji.cs │ ├── WordBlacklist.cs │ ├── AdImage.cs │ ├── Wishlist.cs │ ├── Message.cs │ ├── PostReact.cs │ ├── UserAdView.cs │ ├── Tag.cs │ ├── Town.cs │ ├── Address.cs │ ├── FollowerFollowee.cs │ ├── SubCategory.cs │ ├── PostVote.cs │ ├── UserNotification.cs │ ├── CommentVote.cs │ ├── Notification.cs │ ├── Category.cs │ ├── Feedback.cs │ ├── ApplicationRole.cs │ ├── Comment.cs │ ├── Post.cs │ ├── AYN.Data.Models.csproj │ └── Report.cs ├── AYN.Data │ ├── appsettings.json │ ├── Seeding │ │ ├── Interfaces │ │ │ └── ISeeder.cs │ │ └── Seeders │ │ │ ├── RolesSeeder.cs │ │ │ └── WordBlacklistSeeder.cs │ ├── Configurations │ │ ├── PostConfiguration.cs │ │ ├── FollowerFolloweeConfiguration.cs │ │ └── ApplicationUserConfiguration.cs │ ├── IdentityOptionsProvider.cs │ ├── Migrations │ │ ├── 20210630185440_AddArchivedOnPropertyToTheAd.cs │ │ ├── 20210617212025_AddDeliveryTakePropertyToTheAd.cs │ │ ├── 20210618125632_AddReportTypeToTheReportModel.cs │ │ ├── 20210724153310_AddIsReadPropertyToMessageModel.cs │ │ ├── 20210717155101_RenameUserAvatarAndThumbnailFields.cs │ │ ├── 20210628211541_IncreaseNotificationTextMaxLength.cs │ │ ├── 20210819202135_IncreaseAdDescriptionCharsCount.cs │ │ └── 20210717203405_RenameCategoryPictureFieldToImageUrlAndRemoveLengthRestrictions.cs │ ├── EntityIndexesConfiguration.cs │ ├── DbQueryRunner.cs │ ├── DesignTimeDbContextFactory.cs │ └── Repositories │ │ └── EfDeletableEntityRepository.cs └── AYN.Data.Common │ ├── Models │ ├── IAuditInfo.cs │ ├── IDeletableEntity.cs │ ├── BaseDeletableModel.cs │ └── BaseModel.cs │ ├── IDbQueryRunner.cs │ ├── Repositories │ ├── IDeletableEntityRepository.cs │ └── IRepository.cs │ └── AYN.Data.Common.csproj ├── Tests ├── Sandbox │ ├── SandboxOptions.cs │ └── appsettings.json ├── AYN.Web.Tests │ ├── Properties │ │ └── launchSettings.json │ ├── SeleniumServerFactory.cs │ ├── WebTests.cs │ ├── AYN.Web.Tests.csproj │ └── SeleniumTests.cs └── AYN.Services.Data.Tests │ └── AYN.Services.Data.Tests.csproj ├── AYN.Common ├── GlobalConstants.cs └── AYN.Common.csproj ├── .github └── workflows │ └── dotnet.yml ├── stylecop.json ├── README.md └── LICENSE /Web/AYN.Web/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | this.Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | this.Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AYN.Web.Areas.Identity.Pages.Account -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | this.Layout = "/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/images.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/images.jpg -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AYN.Web.Areas.Identity.Pages.Account.Manage 2 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/mixins/_typography.scss: -------------------------------------------------------------------------------- 1 | @mixin text-color($color) { 2 | color: $color !important; 3 | } -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/care.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/care.gif -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/haha.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/haha.gif -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/like.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/like.gif -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/love.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/love.gif -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/sad.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/sad.gif -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/wow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/wow.gif -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/reacts/angry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/reacts/angry.gif -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Categories/ListSubCategories.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | this.ViewData["Title"] = "List of subcategories"; 3 | } -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/img/upload-file-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/img/upload-file-image.png -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/fonts/linea/linea-basic-10.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/fonts/linea/linea-basic-10.eot -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/fonts/linea/linea-basic-10.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/fonts/linea/linea-basic-10.ttf -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/fonts/linea/linea-basic-10.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/fonts/linea/linea-basic-10.woff -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # IDE0058: Expression value is never used 4 | csharp_style_unused_value_expression_statement_preference = unused_local_variable 5 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/fonts/outline/untitled-font-5.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/fonts/outline/untitled-font-5.eot -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/fonts/outline/untitled-font-5.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/fonts/outline/untitled-font-5.ttf -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/fonts/outline/untitled-font-5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgidelchev/AYN-/HEAD/Web/AYN.Web/wwwroot/fonts/outline/untitled-font-5.woff -------------------------------------------------------------------------------- /Services/AYN.Services.Mapping/IMapTo.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Services.Mapping; 2 | 3 | // ReSharper disable once UnusedTypeParameter 4 | public interface IMapTo 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /Services/AYN.Services.Mapping/IMapFrom.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Services.Mapping; 2 | 3 | // ReSharper disable once UnusedTypeParameter 4 | public interface IMapFrom 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Home/IndexViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels.Home; 2 | 3 | public class IndexViewModel 4 | { 5 | public string Search { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AYN.Web 2 | @using AYN.Web.ViewModels 3 | 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | @addTagHelper *, AYN.Web 6 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/CommentVoteValue.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum CommentVoteValue 4 | { 5 | Up = 0, 6 | Down = 1, 7 | } 8 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/Gender.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum Gender 4 | { 5 | Male = 1, 6 | Female = 2, 7 | Other = 3, 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Sandbox/SandboxOptions.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | 3 | namespace Sandbox; 4 | 5 | [Verb("sandbox", HelpText = "Run sandbox code.")] 6 | public class SandboxOptions 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Sandbox/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=.;Database=AYN;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Web/AYN.Web/Validators/IValidator.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.Validators; 2 | 3 | public interface IValidator 4 | where T : class 5 | { 6 | string Validate(T entity); 7 | } 8 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/AdType.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum AdType 4 | { 5 | Unknown = 1, 6 | Private = 2, 7 | Business = 3, 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AYN.Web 2 | @using AYN.Web.ViewModels 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, AYN.Web 5 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/_GetAllPostsPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Posts.ListUserPostsViewModel 2 | 3 | @foreach (var post in this.Model.UserPosts) 4 | { 5 | 6 | } 7 | 8 |

test

-------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/DeliveryTake.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum DeliveryTake 4 | { 5 | Unknown = 1, 6 | Buyer = 2, 7 | Seller = 3, 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Comments/CreateCommentInputModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels.Comments; 2 | 3 | public class CreateCommentInputModel 4 | { 5 | public string Content { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | 3 | 4 | @model ConfirmEmailModel 5 | @{ 6 | ViewData["Title"] = "Confirm email"; 7 | } 8 | 9 |

@ViewData["Title"]

-------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/PostReacts/PostReactResponseModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels.PostReacts; 2 | 3 | public class PostReactResponseModel 4 | { 5 | public int TotalReacts { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | this.ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@this.ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /Data/AYN.Data/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=DESKTOP-PUM7JOV\\SQLEXPRESS;Database=AYN;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/ProductCondition.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum ProductCondition 4 | { 5 | Unknown = 1, 6 | New = 2, 7 | Used = 3, 8 | Damaged = 4, 9 | } 10 | -------------------------------------------------------------------------------- /Services/AYN.Services.Mapping/IHaveCustomMappings.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | namespace AYN.Services.Mapping; 4 | 5 | public interface IHaveCustomMappings 6 | { 7 | void CreateMappings(IProfileExpression configuration); 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Payments/PaymentViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels.Payments; 2 | 3 | public class PaymentViewModel 4 | { 5 | public string Token { get; set; } 6 | 7 | public decimal Amount { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/ListAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Ads; 4 | 5 | public class ListAdsViewModel 6 | { 7 | public IEnumerable Ads { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Web/AYN.Web/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/Models/IAuditInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AYN.Data.Common.Models; 4 | 5 | public interface IAuditInfo 6 | { 7 | DateTime CreatedOn { get; set; } 8 | 9 | DateTime? ModifiedOn { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Home/IndexPageStatisticsViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels.Home; 2 | 3 | public class IndexPageStatisticsViewModel 4 | { 5 | public int UsersCount { get; set; } 6 | 7 | public int AdsCount { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using AYN.Web.Areas.Identity 3 | @using AYN.Web.Areas.Identity.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | @using AYN.Data.Models 6 | -------------------------------------------------------------------------------- /Web/AYN.Web/Controllers/BaseController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace AYN.Web.Controllers; 5 | 6 | [Authorize] 7 | public class BaseController : Controller 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/Models/IDeletableEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AYN.Data.Common.Models; 4 | 5 | public interface IDeletableEntity 6 | { 7 | bool IsDeleted { get; set; } 8 | 9 | DateTime? DeletedOn { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IUserAdsViewsService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace AYN.Services.Data.Interfaces; 4 | 5 | public interface IUserAdsViewsService 6 | { 7 | Task CreateAsync(string userId, string adId); 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_mixins.scss: -------------------------------------------------------------------------------- 1 | @import "mixins/animations.scss"; 2 | @import "mixins/base.scss"; 3 | @import "mixins/typography.scss"; 4 | @import "mixins/forms.scss"; 5 | @import "mixins/navigation.scss"; 6 | @import "mixins/misc.scss"; 7 | 8 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/ListMoreAdsByUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Ads; 4 | 5 | public class ListMoreAdsByUserViewModel 6 | { 7 | public IEnumerable Ads { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/IDbQueryRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Data.Common; 5 | 6 | public interface IDbQueryRunner : IDisposable 7 | { 8 | Task RunQueryAsync(string query, params object[] parameters); 9 | } 10 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels; 2 | 3 | public class ErrorViewModel 4 | { 5 | public string RequestId { get; set; } 6 | 7 | public bool ShowRequestId 8 | => !string.IsNullOrEmpty(this.RequestId); 9 | } 10 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Notifications/CreateNotificationInputModel.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Web.ViewModels.Notifications; 2 | 3 | public class CreateNotificationInputModel 4 | { 5 | public string Text { get; set; } 6 | 7 | public string RedirectUrl { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/ReactionType.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum ReactionType 4 | { 5 | Like = 1, 6 | Love = 2, 7 | Care = 3, 8 | Haha = 4, 9 | Sad = 5, 10 | Wow = 6, 11 | Angry = 7, 12 | } 13 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Emojis/ListEmojiViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Emojis; 4 | 5 | public class ListEmojiViewModel 6 | { 7 | public IEnumerable Emojis { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/ListFolloweesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Users; 4 | 5 | public class ListFolloweesViewModel : PagingViewModel 6 | { 7 | public IEnumerable Followees { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/ListFollowersViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Users; 4 | 5 | public class ListFollowersViewModel : PagingViewModel 6 | { 7 | public IEnumerable Followers { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Chat/ListChatConversationsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Chat; 4 | 5 | public class ListChatConversationsViewModel 6 | { 7 | public IEnumerable AllChats { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Posts/ListUserPostsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Posts; 4 | 5 | public class ListUserPostsViewModel : PagingViewModel 6 | { 7 | public IEnumerable UserPosts { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Emoji.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Common.Models; 4 | 5 | namespace AYN.Data.Models; 6 | 7 | public class Emoji : BaseDeletableModel 8 | { 9 | [Required] 10 | public string Image { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /Data/AYN.Data/Seeding/Interfaces/ISeeder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Data.Seeding.Interfaces; 5 | 6 | public interface ISeeder 7 | { 8 | Task SeedAsync(ApplicationDbContext dbContext, IServiceProvider serviceProvider); 9 | } 10 | -------------------------------------------------------------------------------- /Services/AYN.Services.Messaging/EmailAttachment.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Services.Messaging; 2 | 3 | public class EmailAttachment 4 | { 5 | public byte[] Content { get; set; } 6 | 7 | public string FileName { get; set; } 8 | 9 | public string MimeType { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/base/_base.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | html,body{ 4 | 5 | } 6 | 7 | body{ 8 | background-color: #ffffff; 9 | font-family: $base-font; 10 | color:$base-color; 11 | font-size:$base-font-size; 12 | overflow-x: hidden; 13 | } 14 | .no-padding{ 15 | padding: 0; 16 | } -------------------------------------------------------------------------------- /AYN.Common/GlobalConstants.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Common; 2 | 3 | public static class GlobalConstants 4 | { 5 | public const string SystemName = "AYN"; 6 | 7 | public const string AdministratorRoleName = "Administrator"; 8 | 9 | public const int PasswordMinLength = 6; 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/ListSuggestionPeopleViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Users; 4 | 5 | public class ListSuggestionPeopleViewModel 6 | { 7 | public IEnumerable SuggestionPeople { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_progress-bars.scss: -------------------------------------------------------------------------------- 1 | .progress { 2 | height: .375rem; 3 | margin-bottom: 1rem; 4 | .progress-bar { 5 | background-color: $bg-primary; 6 | } 7 | &.progress-sm { 8 | height: .2rem; 9 | } 10 | &.progress-lg { 11 | height: .5rem; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Ads/ListAllAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Ads; 4 | 5 | public class ListAllAdsViewModel : PagingViewModel 6 | { 7 | public IEnumerable AllAds { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/ListUserAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using AYN.Web.ViewModels.Ads; 4 | 5 | namespace AYN.Web.ViewModels.Users; 6 | 7 | public class ListUserAdsViewModel 8 | { 9 | public IEnumerable Ads { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | 3 | @model ConfirmEmailChangeModel 4 | 5 | @{ 6 | ViewData["Title"] = "Confirm email change"; 7 | } 8 | 9 |

@ViewData["Title"]

10 | 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Emojis/CreateEmojiInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Emojis; 4 | 5 | public class CreateEmojiInputModel 6 | { 7 | [Required] 8 | public string Emoji { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | 3 | @model RegisterConfirmationModel 4 | 5 | @{ 6 | ViewData["Title"] = "Register confirmation"; 7 | } 8 | 9 |

@ViewData["Title"]

10 | 11 |

Please check your email to confirm your account.

12 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Users/ListAllUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Users; 4 | 5 | public class ListAllUserViewModel : PagingViewModel 6 | { 7 | public IEnumerable AllUsers { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/ICloudinaryService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace AYN.Services.Data.Interfaces; 4 | 5 | public interface ICloudinaryService 6 | { 7 | Task UploadPictureAsync(byte[] data, string fileName, string folderName, int? width, int? height); 8 | } 9 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/Models/BaseDeletableModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AYN.Data.Common.Models; 4 | 5 | public abstract class BaseDeletableModel : BaseModel, IDeletableEntity 6 | { 7 | public bool IsDeleted { get; set; } 8 | 9 | public DateTime? DeletedOn { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IFeedbackService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Web.ViewModels.Feedback; 4 | 5 | namespace AYN.Services.Data.Interfaces; 6 | 7 | public interface IFeedbackService 8 | { 9 | Task CreateAsync(CreateFeedbackInputModel input, string userId); 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ForgotPasswordConfirmation 3 | @{ 4 | ViewData["Title"] = "Forgot password confirmation"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |

9 | Please check your email to reset your password. 10 |

11 | 12 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IPostReactsService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace AYN.Services.Data.Interfaces; 4 | 5 | public interface IPostReactsService 6 | { 7 | Task SetReactAsync(int postId, string userId, int reactValue); 8 | 9 | int GetTotalReacts(int postId); 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Reports/ListAllReportsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Reports; 4 | 5 | public class ListAllReportsViewModel : PagingViewModel 6 | { 7 | public IEnumerable AllReports { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/base/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $base-color:#333; 5 | 6 | $base-font-size:16px; 7 | 8 | $base-font: 'Lato', sans-serif; 9 | 10 | $heading-font: 'Raleway', sans-serif; 11 | 12 | $font-bold:700; 13 | 14 | $theme-color:#ff6666; 15 | 16 | $secondary-color:#F7931D; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IUserLatestAdViewsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Data.Interfaces; 5 | 6 | public interface IUserLatestAdViewsService 7 | { 8 | Task> GetUserLatestAdViews(string userId); 9 | } 10 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Chat/ListBlacklistWordsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Chat; 4 | 5 | public class ListBlacklistWordsViewModel : PagingViewModel 6 | { 7 | public IEnumerable BlacklistedWords { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/mixins/_animations.scss: -------------------------------------------------------------------------------- 1 | @keyframes rotate { 2 | from { 3 | transform: rotate(0deg) 4 | translate(-10px) 5 | rotate(0deg); 6 | } 7 | to { 8 | transform: rotate(360deg) 9 | translate(-10px) 10 | rotate(-360deg); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Addresses/GetAddressesViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Addresses; 5 | 6 | public class GetAddressesViewModel : IMapFrom
7 | { 8 | public int Id { get; set; } 9 | 10 | public string Name { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Notifications/ListAllNotificationsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Notifications; 4 | 5 | public class ListAllNotificationsViewModel : PagingViewModel 6 | { 7 | public IEnumerable Notifications { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/UserWishlistViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using AYN.Web.ViewModels.Ads; 4 | 5 | namespace AYN.Web.ViewModels.Users; 6 | 7 | public class UserWishlistViewModel : PagingViewModel 8 | { 9 | public IEnumerable AdsWishlist { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Categories/ListAllCategoriesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Categories; 4 | 5 | public class ListAllCategoriesViewModel : PagingViewModel 6 | { 7 | public IEnumerable AllCategories { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Comments/EditCommentInputModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | 3 | using AYN.Services.Mapping; 4 | 5 | namespace AYN.Web.ViewModels.Comments; 6 | 7 | public class EditCommentInputModel : IMapFrom 8 | { 9 | public string Id { get; set; } 10 | 11 | public string Content { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Chat/All.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Messages"; 3 | } 4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 |
12 |
-------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Chat/BlacklistWordViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Administration.Chat; 5 | 6 | public class BlacklistWordViewModel : IMapFrom 7 | { 8 | public int Id { get; set; } 9 | 10 | public string Content { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/EditUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Users; 4 | 5 | public class EditUserViewModel 6 | { 7 | public EditUserGeneralInfoViewModel EditUserGeneralInfoViewModel { get; set; } 8 | 9 | public IEnumerable> Towns { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Ads/PromoteAdInputModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace AYN.Web.ViewModels.Administration.Ads; 5 | 6 | public class PromoteAdInputModel 7 | { 8 | public string Id { get; set; } 9 | 10 | [Required] 11 | public DateTime PromoteUntil { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/PostReacts/PostReactInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace AYN.Web.ViewModels.PostReacts; 4 | 5 | public class PostReactInputModel 6 | { 7 | [Required] 8 | public int PostId { get; set; } 9 | 10 | [Required] 11 | [Range(1, 7)] 12 | public int ReactValue { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Categories/CategoryViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Categories; 5 | 6 | public class CategoryViewModel : IMapFrom 7 | { 8 | public int Id { get; set; } 9 | 10 | public string Name { get; set; } 11 | 12 | public string ImageUrl { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace AYN.Web.Areas.Identity.Pages.Account; 5 | 6 | [AllowAnonymous] 7 | public class ForgotPasswordConfirmation : PageModel 8 | { 9 | public void OnGet() 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Categories/ListAllCategoriesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using AYN.Web.ViewModels.SubCategories; 4 | 5 | namespace AYN.Web.ViewModels.Categories; 6 | 7 | public class ListAllCategoriesViewModel 8 | { 9 | public Dictionary> AllCategoriesWithAllSubCategories { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Chat/ChatUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Chat; 5 | 6 | public class ChatUserViewModel : IMapFrom 7 | { 8 | public string Id { get; set; } 9 | 10 | public string UserName { get; set; } 11 | 12 | public string AvatarImageUrl { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/Models/BaseModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace AYN.Data.Common.Models; 5 | 6 | public abstract class BaseModel : IAuditInfo 7 | { 8 | [Key] 9 | public TKey Id { get; set; } 10 | 11 | public DateTime CreatedOn { get; set; } 12 | 13 | public DateTime? ModifiedOn { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Enumerations/ReportType.cs: -------------------------------------------------------------------------------- 1 | namespace AYN.Data.Models.Enumerations; 2 | 3 | public enum ReportType 4 | { 5 | Unknown = 1, 6 | WrongCategory = 2, 7 | WrongSubCategory = 3, 8 | Sexual = 4, 9 | Nudity = 5, 10 | WrongPictures = 6, 11 | ItemDoesNotExists = 7, 12 | Spam = 8, 13 | WrongDescription = 9, 14 | Scam = 10, 15 | } 16 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/WordBlacklist.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Common.Models; 4 | 5 | using static AYN.Common.AttributeConstraints; 6 | 7 | namespace AYN.Data.Models; 8 | 9 | public class WordBlacklist : BaseDeletableModel 10 | { 11 | [Required] 12 | [MaxLength(BlacklistWordMaxLength)] 13 | public string Content { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/AdImage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Common.Models; 4 | 5 | namespace AYN.Data.Models; 6 | 7 | public class AdImage : BaseDeletableModel 8 | { 9 | [Required] 10 | public string AdId { get; set; } 11 | 12 | public virtual Ad Ad { get; set; } 13 | 14 | [Required] 15 | public string ImageUrl { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IAddressesService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Data.Interfaces; 5 | 6 | public interface IAddressesService 7 | { 8 | Task> GetAllByTownIdAsync(int townId); 9 | 10 | Task>> GetAllByTownIdAsKeyValuePairsAsync(int townId); 11 | } 12 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Controllers/AdministrationController.cs: -------------------------------------------------------------------------------- 1 | using AYN.Common; 2 | 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Mvc; 5 | 6 | namespace AYN.Web.Areas.Administration.Controllers; 7 | 8 | [Area("Administration")] 9 | [Authorize(Roles = GlobalConstants.AdministratorRoleName)] 10 | public class AdministrationController : Controller 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IWordsBlacklistService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Data.Interfaces; 5 | 6 | public interface IWordsBlacklistService 7 | { 8 | Task> AllAsync(); 9 | 10 | bool IsGivenWordInBlacklist(string word); 11 | 12 | int Count(); 13 | 14 | Task DeleteAsync(int id); 15 | } 16 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Emojis/EmojiViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | namespace AYN.Web.ViewModels.Administration.Emojis; 7 | 8 | public class EmojiViewModel : IMapFrom 9 | { 10 | public int Id { get; set; } 11 | 12 | public string Image { get; set; } 13 | 14 | public DateTime CreatedOn { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Chat/ChatWithUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AYN.Web.ViewModels.Chat; 4 | 5 | public class ChatWithUserViewModel 6 | { 7 | public ChatUserViewModel User { get; set; } 8 | 9 | public IEnumerable Messages { get; set; } 10 | 11 | public IEnumerable> Emojis { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/SubCategories/CreateSubCategoryInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using static AYN.Common.AttributeConstraints; 4 | 5 | namespace AYN.Web.ViewModels.SubCategories; 6 | 7 | public class CreateSubCategoryInputModel 8 | { 9 | [Required] 10 | [MinLength(CategoryNameMinLength)] 11 | [MaxLength(CategoryNameMaxLength)] 12 | public string Name { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_alerts.scss: -------------------------------------------------------------------------------- 1 | .alert { 2 | @each $color, $value in $bg-colors { 3 | &.alert-#{$color} { 4 | background-color: $value; 5 | color: $white; 6 | border: none; 7 | } 8 | } 9 | a { 10 | color: $white !important; 11 | border-bottom: 1px solid $white !important; 12 | &:hover, 13 | &:focus, 14 | &:active { 15 | border-bottom: 2px solid $white !important; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_tables.scss: -------------------------------------------------------------------------------- 1 | @each $color,$value in $bg-colors { 2 | .table-#{$color} { 3 | @include table-color($value); 4 | } 5 | } 6 | 7 | .table-hover { 8 | @each $color,$value in $bg-colors { 9 | .table-#{$color} { 10 | @include table-hover($value); 11 | } 12 | } 13 | } 14 | 15 | .table-dark, 16 | .table-secondary { 17 | td, 18 | th { 19 | color: $white; 20 | } 21 | } -------------------------------------------------------------------------------- /Services/AYN.Services.Messaging/IEmailSender.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Messaging; 5 | 6 | public interface IEmailSender 7 | { 8 | Task SendEmailAsync( 9 | string from, 10 | string fromName, 11 | string to, 12 | string subject, 13 | string htmlContent, 14 | IEnumerable attachments = null); 15 | } 16 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/GetFollowersViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Users; 5 | 6 | public class GetFollowersViewModel : IMapFrom 7 | { 8 | public string Id { get; set; } 9 | 10 | public string FirstName { get; set; } 11 | 12 | public string LastName { get; set; } 13 | 14 | public string AvatarExtension { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_modals.scss: -------------------------------------------------------------------------------- 1 | .modal { 2 | .modal-dialog { 3 | .modal-content { 4 | border: none; 5 | border-radius: 0rem; 6 | padding: 1rem; 7 | 8 | .modal-header { 9 | border-bottom: none; 10 | } 11 | .modal-footer { 12 | border-top: none; 13 | } 14 | } 15 | } 16 | } 17 | 18 | .modal-backdrop { 19 | background-color: darken($primary, 25%); 20 | &.show { 21 | opacity: 0.8; 22 | } 23 | } -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Categories/AddSubCategoryInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using static AYN.Common.AttributeConstraints; 4 | 5 | namespace AYN.Web.ViewModels.Administration.Categories; 6 | 7 | public class AddSubCategoryInputModel 8 | { 9 | [Required] 10 | [MinLength(CategoryNameMinLength)] 11 | [MaxLength(CategoryNameMaxLength)] 12 | public string Name { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Users/BanUserInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using static AYN.Common.AttributeConstraints; 4 | 5 | namespace AYN.Web.ViewModels.Administration.Users; 6 | 7 | public class BanUserInputModel 8 | { 9 | [Required] 10 | [MinLength(ApplicationUserBlockReasonMinLength)] 11 | [MaxLength(ApplicationUserBlockReasonMaxLength)] 12 | public string BanReason { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Wishlist.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Common.Models; 4 | 5 | namespace AYN.Data.Models; 6 | 7 | public class Wishlist : BaseDeletableModel 8 | { 9 | [Required] 10 | public string UserId { get; set; } 11 | 12 | public virtual ApplicationUser User { get; set; } 13 | 14 | [Required] 15 | public string AdId { get; set; } 16 | 17 | public virtual Ad Ad { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/IdentityHostingStartup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | 3 | [assembly: HostingStartup(typeof(AYN.Web.Areas.Identity.IdentityHostingStartup))] 4 | 5 | namespace AYN.Web.Areas.Identity; 6 | 7 | public class IdentityHostingStartup : IHostingStartup 8 | { 9 | public void Configure(IWebHostBuilder builder) 10 | { 11 | builder.ConfigureServices((context, services) => 12 | { 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_misc.scss: -------------------------------------------------------------------------------- 1 | .circle { 2 | width: .6rem; 3 | height: .6rem; 4 | border-radius: 50%; 5 | background-color: $primary; 6 | } 7 | .bubble { 8 | @include bubble(1.2rem); 9 | } 10 | .big-bubble { 11 | @include bubble(5rem); 12 | } 13 | 14 | .rotate-circle { 15 | position: absolute; 16 | animation: rotate 5s linear infinite; 17 | } 18 | 19 | .rotate-bubble { 20 | position: absolute; 21 | animation: rotate 10s linear infinite; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Message.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Common.Models; 2 | 3 | namespace AYN.Data.Models; 4 | 5 | public class Message : BaseDeletableModel 6 | { 7 | public string SenderId { get; set; } 8 | 9 | public ApplicationUser Sender { get; set; } 10 | 11 | public string ReceiverId { get; set; } 12 | 13 | public ApplicationUser Receiver { get; set; } 14 | 15 | public string Content { get; set; } 16 | 17 | public bool IsRead { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Chat/ChatSendMessageInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using static AYN.Common.AttributeConstraints; 4 | 5 | namespace AYN.Web.ViewModels.Chat; 6 | 7 | public class ChatSendMessageInputModel 8 | { 9 | [Required] 10 | public string Receiver { get; set; } 11 | 12 | [Required] 13 | [MinLength(MessageContentMinLength)] 14 | [MaxLength(MessageContentMaxLength)] 15 | public string Message { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Notifications/GetAllNotificationsForUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | namespace AYN.Web.ViewModels.Notifications; 7 | 8 | public class GetAllNotificationsForUserViewModel : IMapFrom 9 | { 10 | public string Id { get; set; } 11 | 12 | public string Text { get; set; } 13 | 14 | public DateTime CreatedOn { get; set; } 15 | 16 | public string RedirectUrl { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /Services/AYN.Services.Messaging/NullMessageSender.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Messaging; 5 | 6 | public class NullMessageSender : IEmailSender 7 | { 8 | public Task SendEmailAsync( 9 | string from, 10 | string fromName, 11 | string to, 12 | string subject, 13 | string htmlContent, 14 | IEnumerable attachments = null) 15 | => Task.CompletedTask; 16 | } 17 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/Repositories/IDeletableEntityRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | using AYN.Data.Common.Models; 4 | 5 | namespace AYN.Data.Common.Repositories; 6 | 7 | public interface IDeletableEntityRepository : IRepository 8 | where TEntity : class, IDeletableEntity 9 | { 10 | IQueryable AllWithDeleted(); 11 | 12 | IQueryable AllAsNoTrackingWithDeleted(); 13 | 14 | void HardDelete(TEntity entity); 15 | 16 | void Undelete(TEntity entity); 17 | } 18 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/INotificationsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Data.Interfaces; 5 | 6 | public interface INotificationsService 7 | { 8 | Task CreateAsync(string text, string redirectUrl, string toUserId); 9 | 10 | Task> GetAll(string userId); 11 | 12 | int GetCount(string userId); 13 | 14 | Task MarkAsRead(string notificationId); 15 | 16 | Task MarkAllAsRead(string userId); 17 | } 18 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/lib/tinymce/plugins/emoticons/index.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Skipped minification because the original files appears to be already minified. 3 | * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files 4 | */ 5 | // Exports the "emoticons" plugin for usage with module loaders 6 | // Usage: 7 | // CommonJS: 8 | // require('tinymce/plugins/emoticons') 9 | // ES2015: 10 | // import 'tinymce/plugins/emoticons' 11 | require('./plugin.js'); -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/FolloweeViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Users; 5 | 6 | public class FolloweeViewModel : IMapFrom 7 | { 8 | public string FolloweeId { get; set; } 9 | 10 | public string FolloweeFirstName { get; set; } 11 | 12 | public string FolloweeLastName { get; set; } 13 | 14 | public string FolloweeAvatarImageUrl { get; set; } 15 | 16 | public string FolloweeThumbnailImageUrl { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/FollowerViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Users; 5 | 6 | public class FollowerViewModel : IMapFrom 7 | { 8 | public string FollowerId { get; set; } 9 | 10 | public string FollowerFirstName { get; set; } 11 | 12 | public string FollowerLastName { get; set; } 13 | 14 | public string FollowerAvatarImageUrl { get; set; } 15 | 16 | public string FollowerThumbnailImageUrl { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_background.scss: -------------------------------------------------------------------------------- 1 | @each $color,$value in $bg-colors { 2 | .bg-#{$color} { 3 | @include background-color($value); 4 | } 5 | } 6 | 7 | .filter { 8 | display: block; 9 | content: ""; 10 | position: absolute; 11 | top: 0; 12 | bottom: 0; 13 | left: 0; 14 | right: 0; 15 | background-color: $dark; 16 | opacity: .45; 17 | 18 | 19 | @each $color,$value in $theme-colors { 20 | &.filter-#{$color} { 21 | @include filter-color($value); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Data/AYN.Data.Common/Repositories/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | 5 | namespace AYN.Data.Common.Repositories; 6 | 7 | public interface IRepository : IDisposable 8 | where TEntity : class 9 | { 10 | IQueryable All(); 11 | 12 | IQueryable AllAsNoTracking(); 13 | 14 | Task AddAsync(TEntity entity); 15 | 16 | void Update(TEntity entity); 17 | 18 | void Delete(TEntity entity); 19 | 20 | Task SaveChangesAsync(); 21 | } 22 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Reports/CreateReportInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Models.Enumerations; 4 | 5 | using static AYN.Common.AttributeConstraints; 6 | 7 | namespace AYN.Web.ViewModels.Reports; 8 | 9 | public class CreateReportInputModel 10 | { 11 | [Required] 12 | [MinLength(ReportContentMinLength)] 13 | [MaxLength(ReportContentMaxLength)] 14 | public string Description { get; set; } 15 | 16 | [Required] 17 | public ReportType ReportType { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/_SearchBarPartial.cshtml: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/ITownsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Data.Models; 5 | 6 | namespace AYN.Services.Data.Interfaces; 7 | 8 | public interface ITownsService 9 | { 10 | Task>> GetAllAsKeyValuePairsAsync(); 11 | 12 | int GetIdByName(string townName); 13 | 14 | bool IsExisting(int townId); 15 | 16 | bool IsTownContainsGivenAddress(int townId, int addressId); 17 | 18 | Town GetById(int id); 19 | } 20 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/SubCategories/SubCategoryViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | namespace AYN.Web.ViewModels.Administration.SubCategories; 7 | 8 | public class SubCategoryViewModel : IMapFrom 9 | { 10 | public int Id { get; set; } 11 | 12 | public string Name { get; set; } 13 | 14 | public DateTime CreatedOn { get; set; } 15 | 16 | public bool IsDeleted { get; set; } 17 | 18 | public DateTime DeletedOn { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Posts/CreatePostInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using static AYN.Common.AttributeConstraints; 4 | 5 | namespace AYN.Web.ViewModels.Posts; 6 | 7 | public class CreatePostInputModel 8 | { 9 | [Required] 10 | [MinLength(PostTitleMinLength)] 11 | [MaxLength(PostTitleMaxLength)] 12 | public string Title { get; set; } 13 | 14 | [Required] 15 | [MinLength(PostContentMinLength)] 16 | [MaxLength(PostContentMaxLength)] 17 | public string Content { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /Web/AYN.Web/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace AYN.Web; 5 | 6 | public static class Program 7 | { 8 | public static void Main(string[] args) 9 | => CreateHostBuilder(args).Build().Run(); 10 | 11 | public static IHostBuilder CreateHostBuilder(string[] args) 12 | => Host.CreateDefaultBuilder(args) 13 | .ConfigureWebHostDefaults(webBuilder => 14 | { 15 | webBuilder.UseStartup(); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_footers.scss: -------------------------------------------------------------------------------- 1 | .footer-1 { 2 | padding: 2rem 0rem 1rem; 3 | .footer-menu { 4 | margin-bottom: 0rem; 5 | li { 6 | padding: 0rem .8rem; 7 | a { 8 | color: $primary !important; 9 | border-bottom: 0 !important; 10 | &:hover, 11 | &:focus, 12 | &:active { 13 | color: darken($primary, 10%) !important; 14 | } 15 | } 16 | } 17 | } 18 | .copyright { 19 | padding-top: .5rem; 20 | p { 21 | padding: .5rem; 22 | i { 23 | margin: 1rem .1rem; 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/ListGetFromSearchViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using AYN.Web.ViewModels.Categories; 4 | using AYN.Web.ViewModels.SubCategories; 5 | 6 | namespace AYN.Web.ViewModels.Ads; 7 | 8 | public class ListGetFromSearchViewModel : PagingViewModel 9 | { 10 | public IEnumerable AllFromSearch { get; set; } 11 | 12 | public Dictionary> AllCategoriesWithAllSubCategories { get; set; } 13 | 14 | public int TotalResults { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /Data/AYN.Data/Configurations/PostConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace AYN.Data.Configurations; 6 | 7 | public class PostConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder post) 10 | => post.HasOne(p => p.ApplicationUser) 11 | .WithMany(a => a.Posts) 12 | .HasForeignKey(f => f.AddedByUserId) 13 | .OnDelete(DeleteBehavior.Restrict); 14 | } 15 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Chat/ChatConversationsViewModel.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using AYN.Services.Mapping; 3 | 4 | namespace AYN.Web.ViewModels.Chat; 5 | 6 | public class ChatConversationsViewModel : IMapFrom 7 | { 8 | public string Id { get; set; } 9 | 10 | public string UserName { get; set; } 11 | 12 | public string AvatarImageUrl { get; set; } 13 | 14 | public string LastMessage { get; set; } 15 | 16 | public bool IsRead { get; set; } 17 | 18 | public string LastMessageActivity { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_badges.scss: -------------------------------------------------------------------------------- 1 | .badge { 2 | border-radius: .5rem; 3 | padding: .2rem .4rem; 4 | @each $color, $value in $theme-colors { 5 | &.badge-#{$color} { 6 | background-color: transparent; 7 | color: $value; 8 | border: 1px solid rgba($value, 0.4); 9 | } 10 | } 11 | 12 | 13 | &.badge-pill { 14 | @each $color, $value in $theme-colors { 15 | &.badge-#{$color} { 16 | background-color: $value; 17 | color: $white; 18 | } 19 | } 20 | &.badge-light { 21 | color: $dark; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Panels/IndexViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AYN.Web.ViewModels.Administration.Panels; 4 | 5 | public class IndexViewModel 6 | { 7 | public Tuple UsersCounts { get; set; } 8 | 9 | public Tuple AdsCount { get; set; } 10 | 11 | public Tuple ReportsCount { get; set; } 12 | 13 | public Tuple CategoriesCount { get; set; } 14 | 15 | public int EmojisCount { get; set; } 16 | 17 | public int BlacklistedWordsCount { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IEmojisService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Web.ViewModels.Administration.Emojis; 5 | 6 | namespace AYN.Services.Data.Interfaces; 7 | 8 | public interface IEmojisService 9 | { 10 | Task CreateAsync(CreateEmojiInputModel input); 11 | 12 | Task> GetAll(); 13 | 14 | Task>> GetAll(); 15 | 16 | Task Delete(int id); 17 | 18 | int Count(); 19 | 20 | bool IsExisting(string emoji); 21 | } 22 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IWishlistsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Data.Interfaces; 5 | 6 | public interface IWishlistsService 7 | { 8 | Task AddAsync(string adId, string userId); 9 | 10 | Task RemoveAsync(string adId, string userId); 11 | 12 | Task> Wishlist(string userId); 13 | 14 | int Count(string userId); 15 | 16 | bool IsUserHaveGivenAdInHisWishlist(string adId, string userId); 17 | 18 | Task DeleteAsync(string adId); 19 | } 20 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/modules/_typography.scss: -------------------------------------------------------------------------------- 1 | 2 | // TYPOGRAPHY 3 | 4 | ul{ 5 | padding: 0; 6 | margin: 0; 7 | list-style: none; 8 | } 9 | a{ 10 | text-decoration: none; 11 | color:$base-color; 12 | } 13 | a:hover, 14 | a:focus{ 15 | outline: none; 16 | text-decoration: none; 17 | } 18 | h1,h2,h3,h4,h5,h6{ 19 | font-family:$heading-font; 20 | } 21 | h2 { 22 | color: $theme-color; 23 | font-size: 30px; 24 | font-weight:$font-bold; 25 | line-height: 40px; 26 | margin: 0; 27 | padding-bottom: 10px; 28 | } 29 | img{ 30 | border:none; 31 | } 32 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IReportsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using AYN.Web.ViewModels.Reports; 6 | 7 | namespace AYN.Services.Data.Interfaces; 8 | 9 | public interface IReportsService 10 | { 11 | Task CreateAsync(CreateReportInputModel input, string adId, string reportedUserId, string reportingUserId); 12 | 13 | Task> GetAll(); 14 | 15 | int GetCount(); 16 | 17 | Tuple GetCounts(); 18 | 19 | Task DeleteAllByAdId(string adId); 20 | } 21 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/ICommentsService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Web.ViewModels.Comments; 4 | 5 | namespace AYN.Services.Data.Interfaces; 6 | 7 | public interface ICommentsService 8 | { 9 | Task Create(string content, string adId, string userId); 10 | 11 | Task Delete(string commentId); 12 | 13 | Task Vote(string voteValue, string commentId, string userId); 14 | 15 | bool IsCommentExisting(string commentId); 16 | 17 | Task GetByIdAsync(string commentId); 18 | 19 | Task EditAsync(EditCommentInputModel input); 20 | } 21 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/PostReact.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Common.Models; 4 | using AYN.Data.Models.Enumerations; 5 | 6 | namespace AYN.Data.Models; 7 | 8 | public class PostReact : BaseDeletableModel 9 | { 10 | [Required] 11 | public int PostId { get; set; } 12 | 13 | public Post Post { get; set; } 14 | 15 | [Required] 16 | public string ApplicationUserId { get; set; } 17 | 18 | public ApplicationUser ApplicationUser { get; set; } 19 | 20 | [Required] 21 | public ReactionType ReactionType { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/UserAdView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | namespace AYN.Data.Models; 7 | 8 | public class UserAdView : BaseDeletableModel 9 | { 10 | public UserAdView() 11 | { 12 | this.Id = Guid.NewGuid().ToString(); 13 | } 14 | 15 | [Required] 16 | public string UserId { get; set; } 17 | 18 | public virtual ApplicationUser User { get; set; } 19 | 20 | [Required] 21 | public string AdId { get; set; } 22 | 23 | public virtual Ad Ad { get; set; } 24 | } 25 | -------------------------------------------------------------------------------- /Services/AYN.Services.RecurringJobs/AYN.Services.RecurringJobs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/mixins/_misc.scss: -------------------------------------------------------------------------------- 1 | @mixin bubble($width) { 2 | &, 3 | &.bubble-bottom-right, 4 | &.bubble-bottom-left, 5 | &.bubble-top-right, 6 | &.bubble-top-left { 7 | width: $width; 8 | height: $width; 9 | background-color: $primary; 10 | } 11 | 12 | &, 13 | &.bubble-bottom-left  { 14 | border-radius: 50% 50% 50% 0%; 15 | } 16 | 17 | &.bubble-bottom-right { 18 | border-radius: 50% 50% 0% 50%; 19 | } 20 | 21 | &.bubble-top-right { 22 | border-radius: 50% 0% 50% 50%; 23 | } 24 | 25 | &.bubble-top-left { 26 | border-radius: 0% 50% 50% 50%; 27 | } 28 | } -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Tag.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class Tag : BaseDeletableModel 11 | { 12 | [Required] 13 | [MaxLength(TagNameMaxLength)] 14 | public string Name { get; set; } 15 | 16 | public virtual ICollection Ads { get; set; } 17 | = new HashSet(); 18 | 19 | public virtual ICollection Posts { get; set; } 20 | = new HashSet(); 21 | } 22 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/SubCategories/EditSubCategoryInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Web.ViewModels.Administration.SubCategories; 9 | 10 | public class EditSubCategoryInputModel : IMapFrom 11 | { 12 | [Required] 13 | public int Id { get; set; } 14 | 15 | [Required] 16 | [MinLength(CategoryNameMinLength)] 17 | [MaxLength(CategoryNameMaxLength)] 18 | public string Name { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_cards.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | border-radius: 0; 3 | border: none; 4 | box-shadow: 0 0 2rem rgba(0,0,0,.1); 5 | transition: transform 800ms cubic-bezier(.165,.84,.44,1); 6 | .card-header, 7 | .card-footer { 8 | background-color: transparent; 9 | border: none; 10 | padding: 1rem; 11 | border-radius: 0rem; 12 | } 13 | 14 | .card-body { 15 | padding: 1rem; 16 | } 17 | 18 | .card-img { 19 | border-radius: 0; 20 | } 21 | 22 | &:not(.no-hover){ 23 | &:hover { 24 | box-shadow: 0 0 2rem rgba(0,0,0,.19); 25 | transform: scale(1.03); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Town.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class Town : BaseDeletableModel 11 | { 12 | [Required] 13 | [MaxLength(TownNameMaxLength)] 14 | public string Name { get; set; } 15 | 16 | public ICollection Ads { get; set; } 17 | = new HashSet(); 18 | 19 | public virtual ICollection
Addresses { get; set; } 20 | = new HashSet
(); 21 | } 22 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/ListAllAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using AYN.Web.ViewModels.Categories; 4 | using AYN.Web.ViewModels.SubCategories; 5 | 6 | namespace AYN.Web.ViewModels.Ads; 7 | 8 | public class ListAllAdsViewModel : PagingViewModel 9 | { 10 | public IEnumerable AllFromSearch { get; set; } 11 | 12 | public Dictionary> AllCategoriesWithAllSubCategories { get; set; } 13 | 14 | public IEnumerable AvailableLetters { get; set; } 15 | 16 | public int TotalResults { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Address.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class Address : BaseDeletableModel 11 | { 12 | [Required] 13 | [MaxLength(AddressNameMaxLength)] 14 | public string Name { get; set; } 15 | 16 | public virtual ICollection Towns { get; set; } 17 | = new HashSet(); 18 | 19 | public virtual ICollection Ads { get; set; } 20 | = new HashSet(); 21 | } 22 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/js/demo.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // javascript 3 | var slider = document.getElementById('demo-slider'); 4 | noUiSlider.create(slider, { 5 | start: '20', 6 | connect: [true, false], 7 | range: { 8 | 'min': 0, 9 | 'max': 100 10 | } 11 | }); 12 | 13 | // javascript 14 | var slider_handles = document.getElementById('demo-slider-handles'); 15 | noUiSlider.create(slider_handles, { 16 | start: ['20', '40'], 17 | connect: !0, 18 | range: { 19 | 'min': 0, 20 | 'max': 100 21 | } 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/FollowerFollowee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | namespace AYN.Data.Models; 7 | 8 | public class FollowerFollowee : BaseDeletableModel 9 | { 10 | public FollowerFollowee() 11 | { 12 | this.Id = Guid.NewGuid().ToString(); 13 | } 14 | 15 | [Required] 16 | public string FollowerId { get; set; } 17 | 18 | public virtual ApplicationUser Follower { get; set; } 19 | 20 | [Required] 21 | public string FolloweeId { get; set; } 22 | 23 | public virtual ApplicationUser Followee { get; set; } 24 | } 25 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IPostsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Web.ViewModels.Posts; 5 | 6 | namespace AYN.Services.Data.Interfaces; 7 | 8 | public interface IPostsService 9 | { 10 | Task> GetUserAllPostsAsync(string userId); 11 | 12 | Task CreateAsync(string title, string content, string userId); 13 | 14 | Task EditAsync(EditPostInputModel input); 15 | 16 | Task GetById(int id); 17 | 18 | Task DeleteAsync(int postId); 19 | 20 | string GetTitleById(int postId); 21 | 22 | int GetCount(string userId); 23 | } 24 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_dropdown.scss: -------------------------------------------------------------------------------- 1 | .dropdown-toggle:focus { 2 | box-shadow: 0 none; 3 | } 4 | 5 | .dropdown-menu { 6 | border: 1px solid $grey-200; 7 | padding: .8rem; 8 | box-shadow: 0 0 2rem rgba(0,0,0,.1); 9 | transition: all .1s; 10 | a.dropdown-item { 11 | border-bottom: none !important; 12 | border-radius: .2rem; 13 | color: $dark !important; 14 | text-align: left; 15 | padding: 0.6rem; 16 | font-size: 1rem; 17 | line-height: 1rem; 18 | font-weight: 500; 19 | &:hover, 20 | &:focus, 21 | &:active { 22 | color: $info !important; 23 | background-color: $grey-100; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Data/AYN.Data.Models/SubCategory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class SubCategory : BaseDeletableModel 11 | { 12 | [Required] 13 | [MaxLength(CategoryNameMaxLength)] 14 | public string Name { get; set; } 15 | 16 | [Required] 17 | public int CategoryId { get; set; } 18 | 19 | public virtual Category Category { get; set; } 20 | 21 | public virtual ICollection Ads { get; set; } 22 | = new HashSet(); 23 | } 24 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/PostVote.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | namespace AYN.Data.Models; 7 | 8 | public class PostVote : BaseModel 9 | { 10 | public PostVote() 11 | { 12 | this.Id = Guid.NewGuid().ToString(); 13 | } 14 | 15 | [Required] 16 | public int PostId { get; set; } 17 | 18 | public Post Post { get; set; } 19 | 20 | [Required] 21 | public string ApplicationUserId { get; set; } 22 | 23 | public ApplicationUser ApplicationUser { get; set; } 24 | 25 | [Required] 26 | public decimal Value { get; set; } 27 | } 28 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Feedback/CreateFeedbackInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using static AYN.Common.AttributeConstraints; 4 | 5 | namespace AYN.Web.ViewModels.Feedback; 6 | 7 | public class CreateFeedbackInputModel 8 | { 9 | [Required] 10 | [MinLength(FeedbackTitleMinLength)] 11 | [MaxLength(FeedbackTitleMaxLength)] 12 | public string Title { get; set; } 13 | 14 | [Required] 15 | [MinLength(FeedbackContentMinLength)] 16 | [MaxLength(FeedbackContentMaxLength)] 17 | public string Content { get; set; } 18 | 19 | [Required] 20 | [EmailAddress] 21 | public string Email { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Posts/EditPostInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Web.ViewModels.Posts; 9 | 10 | public class EditPostInputModel : IMapFrom 11 | { 12 | public int Id { get; set; } 13 | 14 | [Required] 15 | [MinLength(PostTitleMinLength)] 16 | [MaxLength(PostTitleMaxLength)] 17 | public string Title { get; set; } 18 | 19 | [Required] 20 | [MinLength(PostContentMinLength)] 21 | [MaxLength(PostContentMaxLength)] 22 | public string Content { get; set; } 23 | } 24 | -------------------------------------------------------------------------------- /Web/AYN.Web/Controllers/CategoriesController.cs: -------------------------------------------------------------------------------- 1 | using AYN.Services.Data.Interfaces; 2 | using AYN.Web.ViewModels.SubCategories; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace AYN.Web.Controllers; 6 | 7 | public class CategoriesController : BaseController 8 | { 9 | private readonly ISubCategoriesService subCategoriesService; 10 | 11 | public CategoriesController(ISubCategoriesService subCategoriesService) 12 | => this.subCategoriesService = subCategoriesService; 13 | 14 | [HttpGet] 15 | public IActionResult GetSubCategories(int id) 16 | => this.Json(this.subCategoriesService.GetAllByCategoryId(id)); 17 | } 18 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/GetAdViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | using AutoMapper; 4 | using AYN.Data.Models; 5 | using AYN.Services.Mapping; 6 | 7 | namespace AYN.Web.ViewModels.Ads; 8 | 9 | public class GetAdViewModel : IMapFrom, IHaveCustomMappings 10 | { 11 | public string Id { get; set; } 12 | 13 | public string Name { get; set; } 14 | 15 | public string ImageUrl { get; set; } 16 | 17 | public void CreateMappings(IProfileExpression configuration) 18 | { 19 | configuration.CreateMap() 20 | .ForMember(m => m.ImageUrl, opt => opt.MapFrom(o => o.Images.FirstOrDefault().ImageUrl)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Chat/BlacklistedWords.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Chat.ListBlacklistWordsViewModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Blacklisted Words"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 |
12 | @foreach (var word in this.Model.BlacklistedWords) 13 | { 14 |
15 | @word.Content 16 |
17 | } 18 |
19 | 20 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/SubCategories/SubCategoryViewModel.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using AYN.Data.Models; 3 | using AYN.Services.Mapping; 4 | 5 | namespace AYN.Web.ViewModels.SubCategories; 6 | 7 | public class SubCategoryViewModel : IMapFrom, IHaveCustomMappings 8 | { 9 | public int Id { get; set; } 10 | 11 | public string Name { get; set; } 12 | 13 | public int AdsCount { get; set; } 14 | 15 | public void CreateMappings(IProfileExpression configuration) 16 | { 17 | configuration 18 | .CreateMap() 19 | .ForMember(m => m.AdsCount, opt => opt.MapFrom(o => o.Ads.Count)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/_DeleteConfirmationPartial.cshtml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AYN.Common/AYN.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/_AlphabetFilterPartial.cshtml: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | @for (var i = 'A'; i <= 'Z'; i++) 5 | { 6 | @if (this.Model.AvailableLetters.Contains(i.ToString())) 7 | { 8 | @i 9 | } 10 | else 11 | { 12 |

@i

13 | } 14 | } 15 |
16 |
17 |
-------------------------------------------------------------------------------- /Services/AYN.Services/AYN.Services.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Data/AYN.Data/IdentityOptionsProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | using static AYN.Common.GlobalConstants; 4 | 5 | namespace AYN.Data; 6 | 7 | public static class IdentityOptionsProvider 8 | { 9 | public static void GetIdentityOptions(IdentityOptions options) 10 | { 11 | options.Password.RequireDigit = false; 12 | options.Password.RequireLowercase = false; 13 | options.Password.RequireUppercase = false; 14 | options.Password.RequireNonAlphanumeric = false; 15 | options.Password.RequiredLength = PasswordMinLength; 16 | options.SignIn.RequireConfirmedAccount = true; 17 | options.User.RequireUniqueEmail = true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/UserNotification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | namespace AYN.Data.Models; 7 | 8 | public class UserNotification : BaseDeletableModel 9 | { 10 | public UserNotification() 11 | { 12 | this.Id = Guid.NewGuid().ToString(); 13 | } 14 | 15 | [Required] 16 | public string ApplicationUserId { get; set; } 17 | 18 | public virtual ApplicationUser ApplicationUser { get; set; } 19 | 20 | [Required] 21 | public string NotificationId { get; set; } 22 | 23 | public virtual Notification Notification { get; set; } 24 | 25 | [Required] 26 | public bool IsRead { get; set; } 27 | } 28 | -------------------------------------------------------------------------------- /Web/AYN.Web/bundleconfig.json: -------------------------------------------------------------------------------- 1 | // Configure bundling and minification for the project. 2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241 3 | [ 4 | { 5 | "outputFileName": "wwwroot/css/site.min.css", 6 | // An array of relative input file paths. Globbing patterns supported 7 | "inputFiles": [ 8 | "wwwroot/css/site.css" 9 | ] 10 | }, 11 | { 12 | "outputFileName": "wwwroot/js/site.min.js", 13 | "inputFiles": [ 14 | "wwwroot/js/site.js" 15 | ], 16 | // Optionally specify minification options 17 | "minify": { 18 | "enabled": true, 19 | "renameLocals": true 20 | }, 21 | // Optionally generate .map file 22 | "sourceMap": false 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Components/GetRecentAds/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Ads.ListAdsViewModel 2 | 3 |
4 | @foreach (var ad in this.Model.Ads) 5 | { 6 |
7 |
8 |
9 | Card image cap 10 |
11 |
12 | @ad.Name
13 | @ad.Price$ 14 |
15 |
16 |
17 | } 18 |
-------------------------------------------------------------------------------- /Data/AYN.Data.Models/CommentVote.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | using AYN.Data.Models.Enumerations; 6 | 7 | namespace AYN.Data.Models; 8 | 9 | public class CommentVote : BaseDeletableModel 10 | { 11 | public CommentVote() 12 | { 13 | this.Id = Guid.NewGuid().ToString(); 14 | } 15 | 16 | [Required] 17 | public string CommentId { get; set; } 18 | 19 | public Comment Comment { get; set; } 20 | 21 | [Required] 22 | public string ApplicationUserId { get; set; } 23 | 24 | public ApplicationUser ApplicationUser { get; set; } 25 | 26 | [Required] 27 | public CommentVoteValue Value { get; set; } 28 | } 29 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Categories/EditCategoryInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | using Microsoft.AspNetCore.Http; 6 | 7 | using static AYN.Common.AttributeConstraints; 8 | 9 | namespace AYN.Web.ViewModels.Administration.Categories; 10 | 11 | public class EditCategoryInputModel : IMapFrom 12 | { 13 | [Required] 14 | public int Id { get; set; } 15 | 16 | [Required] 17 | [MinLength(CategoryNameMinLength)] 18 | [MaxLength(CategoryNameMaxLength)] 19 | public string Name { get; set; } 20 | 21 | public string PictureExtension { get; set; } 22 | 23 | public IFormFile Picture { get; set; } 24 | } 25 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/GetAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | using AutoMapper; 4 | using AYN.Data.Models; 5 | using AYN.Services.Mapping; 6 | 7 | namespace AYN.Web.ViewModels.Ads; 8 | 9 | public class GetAdsViewModel : IMapFrom, IHaveCustomMappings 10 | { 11 | public string Id { get; set; } 12 | 13 | public string Name { get; set; } 14 | 15 | public string TitleImageUrl { get; set; } 16 | 17 | public decimal Price { get; set; } 18 | 19 | public void CreateMappings(IProfileExpression configuration) 20 | { 21 | configuration.CreateMap() 22 | .ForMember(m => m.TitleImageUrl, opt => opt.MapFrom(o => o.Images.FirstOrDefault().ImageUrl)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Web/AYN.Web/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | using AYN.Web.ViewModels; 4 | using AYN.Web.ViewModels.Home; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.Controllers; 8 | 9 | public class HomeController : Controller 10 | { 11 | public IActionResult Index() 12 | { 13 | return this.View(new IndexViewModel { Search = string.Empty }); 14 | } 15 | 16 | public IActionResult Privacy() 17 | => this.View(); 18 | 19 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 20 | public IActionResult Error() 21 | => this.View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? this.HttpContext.TraceIdentifier }); 22 | } 23 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_navbars.scss: -------------------------------------------------------------------------------- 1 | .navbar { 2 | padding: 1.2rem 1rem; 3 | 4 | .navbar-brand { 5 | font-weight: 800; 6 | } 7 | 8 | .nav-link { 9 | font-weight: 500; 10 | @include opacity(0.9); 11 | } 12 | } 13 | 14 | .navbar-dark { 15 | .navbar-nav { 16 | .nav-link { 17 | color: rgba($white, 0.9); 18 | 19 | &:hover, 20 | &:active, 21 | &:focus { 22 | color: rgba($white, 1); 23 | } 24 | } 25 | } 26 | } 27 | 28 | .navbar-light { 29 | .navbar-nav { 30 | .nav-link { 31 | color: rgba($dark, 0.9); 32 | &:hover, 33 | &:active, 34 | &:focus { 35 | color: rgba($dark, 1); 36 | } 37 | } 38 | } 39 | } 40 | 41 | .navbar-transparent { 42 | background-color: transparent; 43 | } -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Users/GetAllUsersViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | namespace AYN.Web.ViewModels.Administration.Users; 7 | 8 | public class GetAllUsersViewModel : IMapFrom 9 | { 10 | public string Id { get; set; } 11 | 12 | public string Username { get; set; } 13 | 14 | public string FirstName { get; set; } 15 | 16 | public string LastName { get; set; } 17 | 18 | public string AvatarImageUrl { get; set; } 19 | 20 | public DateTime CreatedOn { get; set; } 21 | 22 | public string Email { get; set; } 23 | 24 | public string PhoneNumber { get; set; } 25 | 26 | public bool IsBanned { get; set; } 27 | } 28 | -------------------------------------------------------------------------------- /Web/AYN.Web/Controllers/TownsController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Addresses; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.Controllers; 8 | 9 | public class TownsController : BaseController 10 | { 11 | private readonly IAddressesService addressesService; 12 | 13 | public TownsController(IAddressesService addressesService) 14 | => this.addressesService = addressesService; 15 | 16 | [HttpGet] 17 | public async Task GetAddresses(int id) 18 | { 19 | var addresses = await this.addressesService.GetAllByTownIdAsync(id); 20 | return this.Json(addresses); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Components/GetRecentlyPromotedAds/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Ads.ListAdsViewModel 2 | 3 |
4 | @foreach (var ad in this.Model.Ads) 5 | { 6 |
7 |
8 |
9 | Card image cap 10 |
11 |
12 | @ad.Name
13 | @ad.Price$ 14 |
15 |
16 |
17 | } 18 |
-------------------------------------------------------------------------------- /Data/AYN.Data.Models/Notification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | using AYN.Data.Common.Models; 6 | 7 | using static AYN.Common.AttributeConstraints; 8 | 9 | namespace AYN.Data.Models; 10 | 11 | public class Notification : BaseDeletableModel 12 | { 13 | public Notification() 14 | { 15 | this.Id = Guid.NewGuid().ToString(); 16 | } 17 | 18 | [Required] 19 | [MaxLength(NotificationTextMaxLength)] 20 | public string Text { get; set; } 21 | 22 | [Required] 23 | public string RedirectUrl { get; set; } 24 | 25 | public ICollection Users { get; set; } 26 | = new HashSet(); 27 | } 28 | -------------------------------------------------------------------------------- /Web/AYN.Web/Infrastructure/Extensions/ClaimsPrincipalExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | 3 | using AYN.Common; 4 | 5 | namespace AYN.Web.Infrastructure.Extensions; 6 | 7 | public static class ClaimsPrincipalExtensions 8 | { 9 | public static string GetId(this ClaimsPrincipal user) 10 | => user.FindFirstValue(ClaimTypes.NameIdentifier); 11 | 12 | public static string GetEmail(this ClaimsPrincipal user) 13 | => user.FindFirstValue(ClaimTypes.Email); 14 | 15 | public static bool IsUserAuthenticated(this ClaimsPrincipal user) 16 | => user.Identity.IsAuthenticated; 17 | 18 | public static bool IsAdmin(this ClaimsPrincipal user) 19 | => user.IsInRole(GlobalConstants.AdministratorRoleName); 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v3 21 | with: 22 | dotnet-version: 6.0.x 23 | - name: Restore dependencies 24 | run: dotnet restore 25 | - name: Build 26 | run: dotnet build --no-restore 27 | - name: Test 28 | run: dotnet test --no-build --verbosity normal 29 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_pagination.scss: -------------------------------------------------------------------------------- 1 | .pagination { 2 | .page-item { 3 | a.page-link { 4 | border: none; 5 | border-bottom: 0px; 6 | color: $grey-400; 7 | padding: .5rem .9rem; 8 | &:hover, 9 | &:focus { 10 | background-color: transparent; 11 | color: $primary; 12 | border-bottom: 0px; 13 | box-shadow: none; 14 | } 15 | } 16 | &.active { 17 | a.page-link { 18 | background-color: $primary; 19 | border-radius: .25rem; 20 | box-shadow: 0px 3px 5px rgba($primary, 0.2); 21 | color: $white; 22 | } 23 | } 24 | } 25 | 26 | &.pagination-lg { 27 | a.page-link { 28 | padding: .6rem 1.2rem; 29 | } 30 | } 31 | &.pagination-sm { 32 | a.page-link { 33 | padding: .2rem .6rem; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_tooltips.scss: -------------------------------------------------------------------------------- 1 | .tooltip-inner { 2 | background-color: $bg-primary; 3 | border-radius: .25rem; 4 | } 5 | 6 | .tooltip.bs-tooltip-auto[x-placement^=top] .arrow::before, 7 | .tooltip.bs-tooltip-top .arrow::before { 8 | border-top-color: $bg-primary; 9 | } 10 | .tooltip.bs-tooltip-auto[x-placement^=right] .arrow::before, .tooltip.bs-tooltip-right .arrow::before { 11 | border-right-color: $bg-primary; 12 | } 13 | 14 | .tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::before, .tooltip.bs-tooltip-bottom .arrow::before { 15 | border-bottom-color: $bg-primary; 16 | } 17 | 18 | .tooltip.bs-tooltip-auto[x-placement^=left] .arrow::before, .tooltip.bs-tooltip-left .arrow::before { 19 | border-left-color: $bg-primary; 20 | } -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Components/GetHomePageStatistics/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Home.IndexPageStatisticsViewModel 2 | 3 |
4 |
5 |
6 |
7 |

@Model.UsersCount

Active Users in the platform
8 |
9 |
10 |
11 |
12 |
13 |
14 |

@Model.AdsCount

Active Ads in the platform
15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/lazy.scss: -------------------------------------------------------------------------------- 1 | @import 'custom/variables'; 2 | @import 'custom/mixins'; 3 | 4 | // Core CSS 5 | @import "custom/background"; 6 | @import "custom/buttons"; 7 | @import "custom/inputs"; 8 | @import "custom/typography"; 9 | @import "custom/sliders"; 10 | @import "custom/checkbox-radio-toggle"; 11 | @import "custom/navbars"; 12 | @import "custom/tables"; 13 | @import "custom/navs"; 14 | @import "custom/pagination"; 15 | @import "custom/badges"; 16 | @import "custom/progress-bars"; 17 | @import "custom/alerts"; 18 | @import "custom/tooltips"; 19 | @import "custom/popovers"; 20 | @import "custom/modals"; 21 | @import "custom/cards"; 22 | @import "custom/dropdown"; 23 | 24 | //misc 25 | @import "custom/misc"; 26 | 27 | //components 28 | @import "custom/footers"; -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IMessagesService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace AYN.Services.Data.Interfaces; 5 | 6 | public interface IMessagesService 7 | { 8 | Task CreateAsync(string content, string senderId, string receiverId); 9 | 10 | Task GetLastActivityAsync(string currentUserId, string userId); 11 | 12 | Task GetLastMessageAsync(string currentUserId, string userId); 13 | 14 | Task> GetAllWithUserAsync(string currentUserId, string userId); 15 | 16 | Task> GetAllAsync(string currentUserId); 17 | 18 | bool IsAllMessagesRead(string currentUserId, string userId); 19 | 20 | int GetUnreadMessagesCount(string userId); 21 | } 22 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Categories/GetAllCategoriesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using AYN.Data.Models; 5 | using AYN.Services.Mapping; 6 | using AYN.Web.ViewModels.Administration.SubCategories; 7 | 8 | namespace AYN.Web.ViewModels.Administration.Categories; 9 | 10 | public class GetAllCategoriesViewModel : IMapFrom 11 | { 12 | public int Id { get; set; } 13 | 14 | public string Name { get; set; } 15 | 16 | public string PictureExtension { get; set; } 17 | 18 | public DateTime CreatedOn { get; set; } 19 | 20 | public bool IsDeleted { get; set; } 21 | 22 | public DateTime DeletedOn { get; set; } 23 | 24 | public ICollection SubCategories { get; set; } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/AYN.Web.Tests/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5995/", 7 | "sslPort": 44357 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "AYN.Web.Tests": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:61094/" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Web/AYN.Web/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:19901", 7 | "sslPort": 44319 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "AYN.Web": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Services/AYN.Services.Mapping/AYN.Services.Mapping.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Services/AYN.Services.Messaging/AYN.Services.Messaging.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Data/AYN.Data.Common/AYN.Data.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Category.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class Category : BaseDeletableModel 11 | { 12 | [Required] 13 | [MaxLength(CategoryNameMaxLength)] 14 | public string Name { get; set; } 15 | 16 | [Required] 17 | public string ImageUrl { get; set; } 18 | 19 | public virtual ICollection Ads { get; set; } 20 | = new HashSet(); 21 | 22 | public virtual ICollection SubCategories { get; set; } 23 | = new HashSet(); 24 | 25 | public virtual ICollection Posts { get; set; } 26 | = new HashSet(); 27 | } 28 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210630185440_AddArchivedOnPropertyToTheAd.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace AYN.Data.Migrations 6 | { 7 | public partial class AddArchivedOnPropertyToTheAd : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AddColumn( 12 | name: "ArchivedOn", 13 | table: "Ads", 14 | type: "datetime2", 15 | nullable: true); 16 | } 17 | 18 | protected override void Down(MigrationBuilder migrationBuilder) 19 | { 20 | migrationBuilder.DropColumn( 21 | name: "ArchivedOn", 22 | table: "Ads"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetRecentAdsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Ads; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.ViewComponents; 8 | 9 | public class GetRecentAdsViewComponent : ViewComponent 10 | { 11 | private readonly IAdsService adsService; 12 | 13 | public GetRecentAdsViewComponent(IAdsService adsService) 14 | { 15 | this.adsService = adsService; 16 | } 17 | 18 | public async Task InvokeAsync() 19 | { 20 | var viewModel = new ListAdsViewModel 21 | { 22 | Ads = await this.adsService 23 | .GetRecent12AdsAsync(), 24 | }; 25 | 26 | return this.View(viewModel); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Feedback.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class Feedback : BaseDeletableModel 11 | { 12 | public Feedback() 13 | { 14 | this.Id = Guid.NewGuid().ToString(); 15 | } 16 | 17 | [Required] 18 | [MaxLength(FeedbackTitleMaxLength)] 19 | public string Title { get; set; } 20 | 21 | [Required] 22 | public string Email { get; set; } 23 | 24 | [Required] 25 | [MaxLength(FeedbackContentMaxLength)] 26 | public string Content { get; set; } 27 | 28 | [Required] 29 | public string AddedByUserId { get; set; } 30 | 31 | public ApplicationUser AddedByUser { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210617212025_AddDeliveryTakePropertyToTheAd.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class AddDeliveryTakePropertyToTheAd : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "DeliveryTake", 11 | table: "Ads", 12 | type: "int", 13 | nullable: false, 14 | defaultValue: 0); 15 | } 16 | 17 | protected override void Down(MigrationBuilder migrationBuilder) 18 | { 19 | migrationBuilder.DropColumn( 20 | name: "DeliveryTake", 21 | table: "Ads"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210618125632_AddReportTypeToTheReportModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class AddReportTypeToTheReportModel : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "ReportType", 11 | table: "Reports", 12 | type: "int", 13 | nullable: false, 14 | defaultValue: 0); 15 | } 16 | 17 | protected override void Down(MigrationBuilder migrationBuilder) 18 | { 19 | migrationBuilder.DropColumn( 20 | name: "ReportType", 21 | table: "Reports"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210724153310_AddIsReadPropertyToMessageModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class AddIsReadPropertyToMessageModel : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "IsRead", 11 | table: "Message", 12 | type: "bit", 13 | nullable: false, 14 | defaultValue: false); 15 | } 16 | 17 | protected override void Down(MigrationBuilder migrationBuilder) 18 | { 19 | migrationBuilder.DropColumn( 20 | name: "IsRead", 21 | table: "Message"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Chat/ChatMessagesWithUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | using Ganss.Xss; 6 | 7 | namespace AYN.Web.ViewModels.Chat; 8 | 9 | public class ChatMessagesWithUserViewModel : IMapFrom 10 | { 11 | private readonly IHtmlSanitizer sanitizer; 12 | 13 | public ChatMessagesWithUserViewModel() 14 | { 15 | this.sanitizer = new HtmlSanitizer(); 16 | } 17 | 18 | public string Content { get; set; } 19 | 20 | public string SanitizedContent 21 | => this.sanitizer.Sanitize(this.Content); 22 | 23 | public string SenderId { get; set; } 24 | 25 | public string SenderUserName { get; set; } 26 | 27 | public string SenderAvatarImageUrl { get; set; } 28 | 29 | public DateTime CreatedOn { get; set; } 30 | } 31 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/GetSuggestionPeopleViewModel.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using AYN.Data.Models; 3 | using AYN.Services.Mapping; 4 | 5 | namespace AYN.Web.ViewModels.Users; 6 | 7 | public class GetSuggestionPeopleViewModel : IMapFrom, IHaveCustomMappings 8 | { 9 | public string Id { get; set; } 10 | 11 | public string FirstName { get; set; } 12 | 13 | public string LastName { get; set; } 14 | 15 | public string AvatarExtension { get; set; } 16 | 17 | public int FollowersCount { get; set; } 18 | 19 | public void CreateMappings(IProfileExpression configuration) 20 | { 21 | configuration 22 | .CreateMap() 23 | .ForMember(m => m.FollowersCount, opt => opt.MapFrom(o => o.Followers.Count)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/ApplicationRole.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable VirtualMemberCallInConstructor 2 | using System; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | using AYN.Data.Common.Models; 6 | 7 | using Microsoft.AspNetCore.Identity; 8 | 9 | namespace AYN.Data.Models; 10 | 11 | public class ApplicationRole : IdentityRole, IAuditInfo, IDeletableEntity 12 | { 13 | public ApplicationRole() 14 | : this(null) 15 | { 16 | } 17 | 18 | public ApplicationRole(string name) 19 | : base(name) 20 | { 21 | this.Id = Guid.NewGuid().ToString(); 22 | } 23 | 24 | [Required] 25 | public DateTime CreatedOn { get; set; } 26 | 27 | public DateTime? ModifiedOn { get; set; } 28 | 29 | [Required] 30 | public bool IsDeleted { get; set; } 31 | 32 | public DateTime? DeletedOn { get; set; } 33 | } 34 | -------------------------------------------------------------------------------- /Data/AYN.Data/Configurations/FollowerFolloweeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace AYN.Data.Configurations; 6 | 7 | public class FollowerFolloweeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder followerFollowee) 10 | { 11 | followerFollowee.HasOne(ff => ff.Followee) 12 | .WithMany(ff => ff.Followings) 13 | .HasForeignKey(ff => ff.FolloweeId) 14 | .OnDelete(DeleteBehavior.Restrict); 15 | 16 | followerFollowee.HasOne(ff => ff.Follower) 17 | .WithMany(ff => ff.Followers) 18 | .HasForeignKey(ff => ff.FollowerId) 19 | .OnDelete(DeleteBehavior.Restrict); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Data/AYN.Data/EntityIndexesConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | using AYN.Data.Common.Models; 4 | 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace AYN.Data; 8 | 9 | internal static class EntityIndexesConfiguration 10 | { 11 | public static void Configure(ModelBuilder modelBuilder) 12 | { 13 | // IDeletableEntity.IsDeleted index 14 | var deletableEntityTypes = modelBuilder 15 | .Model 16 | .GetEntityTypes() 17 | .Where(et => et.ClrType != null && typeof(IDeletableEntity).IsAssignableFrom(et.ClrType)); 18 | 19 | foreach (var deletableEntityType in deletableEntityTypes) 20 | { 21 | modelBuilder 22 | .Entity(deletableEntityType.ClrType) 23 | .HasIndex(nameof(IDeletableEntity.IsDeleted)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetRecentlyPromotedAdsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Ads; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.ViewComponents; 8 | 9 | public class GetRecentlyPromotedAdsViewComponent : ViewComponent 10 | { 11 | private readonly IAdsService adsService; 12 | 13 | public GetRecentlyPromotedAdsViewComponent( 14 | IAdsService adsService) 15 | { 16 | this.adsService = adsService; 17 | } 18 | 19 | public async Task InvokeAsync() 20 | { 21 | var viewModel = new ListAdsViewModel 22 | { 23 | Ads = await this.adsService.GetRecent12PromotedAdsAsync(), 24 | }; 25 | 26 | return this.View(viewModel); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Categories/CreateCategoryInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | using AYN.Web.ViewModels.SubCategories; 6 | using Microsoft.AspNetCore.Http; 7 | 8 | using static AYN.Common.AttributeConstraints; 9 | 10 | namespace AYN.Web.ViewModels.Administration.Categories; 11 | 12 | public class CreateCategoryInputModel 13 | { 14 | [Required] 15 | [MinLength(CategoryNameMinLength)] 16 | [MaxLength(CategoryNameMaxLength)] 17 | public string Name { get; set; } 18 | 19 | [Required] 20 | public IFormFile Picture { get; set; } 21 | 22 | [DisplayName("SubCategory")] 23 | public ICollection SubCategories { get; set; } 24 | = new HashSet(); 25 | } 26 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetUserAllAdsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Ads; 5 | using AYN.Web.ViewModels.Users; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.ViewComponents; 9 | 10 | public class GetUserAllAdsViewComponent : ViewComponent 11 | { 12 | private readonly IAdsService adsService; 13 | 14 | public GetUserAllAdsViewComponent( 15 | IAdsService adsService) 16 | { 17 | this.adsService = adsService; 18 | } 19 | 20 | public async Task InvokeAsync(string userId) 21 | { 22 | var viewModel = new ListUserAdsViewModel 23 | { 24 | Ads = await this.adsService.GetUserAllAds(userId), 25 | }; 26 | 27 | return this.View(viewModel); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/mixins/_navigation.scss: -------------------------------------------------------------------------------- 1 | @mixin nav-tabs-style($color) { 2 | &.active { 3 | &, 4 | &:hover { 5 | border-bottom: 2px solid $color; 6 | border-color: $color; 7 | font-weight: bold; 8 | color: $color; 9 | } 10 | i { 11 | color: $color; 12 | } 13 | } 14 | 15 | &:hover { 16 | border-bottom: 1px solid $color; 17 | color: $color; 18 | i { 19 | color: $color; 20 | } 21 | } 22 | } 23 | 24 | @mixin nav-pills-style($color) { 25 | &.active { 26 | background-color: $color; 27 | box-shadow: 0px 3px 5px rgba($color, 0.2); 28 | color: $white; 29 | font-weight: bold; 30 | &:hover, 31 | &:focus, 32 | i { 33 | color: $white !important; 34 | } 35 | } 36 | 37 | &:hover, 38 | &:focus { 39 | color: $color; 40 | i { 41 | color: $color; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Reports/GetAllReportsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Data.Models.Enumerations; 5 | using AYN.Services.Mapping; 6 | 7 | namespace AYN.Web.ViewModels.Administration.Reports; 8 | 9 | public class GetAllReportsViewModel : IMapFrom 10 | { 11 | public string Id { get; set; } 12 | 13 | public string Description { get; set; } 14 | 15 | public string ReportingUserId { get; set; } 16 | 17 | public string ReportingUserUsername { get; set; } 18 | 19 | public string ReportedUserId { get; set; } 20 | 21 | public string ReportedUserUsername { get; set; } 22 | 23 | public string ReportedAdId { get; set; } 24 | 25 | public string ReportedAdName { get; set; } 26 | 27 | public DateTime CreatedOn { get; set; } 28 | 29 | public ReportType ReportType { get; set; } 30 | } 31 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetUserRecentAdsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Ads; 5 | using AYN.Web.ViewModels.Users; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.ViewComponents; 9 | 10 | public class GetUserRecentAdsViewComponent : ViewComponent 11 | { 12 | private readonly IAdsService adsService; 13 | 14 | public GetUserRecentAdsViewComponent( 15 | IAdsService adsService) 16 | { 17 | this.adsService = adsService; 18 | } 19 | 20 | public async Task InvokeAsync(string userId) 21 | { 22 | var viewModel = new ListUserAdsViewModel 23 | { 24 | Ads = await this.adsService.GetUserRecentAds(userId), 25 | }; 26 | 27 | return this.View(viewModel); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/MoreAdsByUserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | using AutoMapper; 4 | using AYN.Data.Models; 5 | using AYN.Services.Mapping; 6 | 7 | namespace AYN.Web.ViewModels.Ads; 8 | 9 | public class MoreAdsByUserViewModel : IMapFrom, IHaveCustomMappings 10 | { 11 | public string Id { get; set; } 12 | 13 | public string Name { get; set; } 14 | 15 | public string ShortName 16 | => this.Name.Length >= 4 ? this.Name.Substring(0, 4) : this.Name; 17 | 18 | public decimal Price { get; set; } 19 | 20 | public string TitleImageUrl { get; set; } 21 | 22 | public void CreateMappings(IProfileExpression configuration) 23 | { 24 | configuration 25 | .CreateMap() 26 | .ForMember(m => m.TitleImageUrl, opt => opt.MapFrom(o => o.Images.FirstOrDefault().ImageUrl)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/lib/tinymce/plugins/hr/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | * 7 | * Version: 5.2.0 (2020-02-13) 8 | */ 9 | !function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),o=function(n){n.addCommand("InsertHorizontalRule",function(){n.execCommand("mceInsertContent",!1,"
")})},t=function(n){n.ui.registry.addButton("hr",{icon:"horizontal-rule",tooltip:"Horizontal line",onAction:function(){return n.execCommand("InsertHorizontalRule")}}),n.ui.registry.addMenuItem("hr",{icon:"horizontal-rule",text:"Horizontal line",onAction:function(){return n.execCommand("InsertHorizontalRule")}})};!function e(){n.add("hr",function(n){o(n),t(n)})}()}(); -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Administration/Ads/GetAllAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using AYN.Data.Models; 4 | using AYN.Services.Mapping; 5 | 6 | namespace AYN.Web.ViewModels.Administration.Ads; 7 | 8 | public class GetAllAdsViewModel : IMapFrom 9 | { 10 | public string Id { get; set; } 11 | 12 | public string Name { get; set; } 13 | 14 | public string AddedByUserId { get; set; } 15 | 16 | public string AddedByUserUsername { get; set; } 17 | 18 | public DateTime CreatedOn { get; set; } 19 | 20 | public bool IsArchived { get; set; } 21 | 22 | public DateTime? ArchivedOn { get; set; } 23 | 24 | public bool IsDeleted { get; set; } 25 | 26 | public DateTime? DeletedOn { get; set; } 27 | 28 | public bool IsPromoted { get; set; } 29 | 30 | public DateTime? PromotedOn { get; set; } 31 | 32 | public DateTime? PromotedUntil { get; set; } 33 | } 34 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ForgotPasswordModel 3 | @{ 4 | ViewData["Title"] = "Forgot your password?"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |

Enter your email.

9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 | 24 | @section Scripts { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Web/AYN.Web/Controllers/ReportsController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.Infrastructure.Extensions; 5 | using AYN.Web.ViewModels.Reports; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.Controllers; 9 | 10 | public class ReportsController : BaseController 11 | { 12 | private readonly IReportsService reportsService; 13 | 14 | public ReportsController(IReportsService reportsService) 15 | => this.reportsService = reportsService; 16 | 17 | [HttpGet] 18 | public IActionResult Create() 19 | => this.View(); 20 | 21 | [HttpPost] 22 | public async Task Create(CreateReportInputModel input, string id, string reportedUser) 23 | { 24 | await this.reportsService.CreateAsync(input, id, reportedUser, this.User.GetId()); 25 | return this.Redirect("/"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Web/AYN.Web/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=DESKTOP-PUM7JOV\\SQLEXPRESS;Database=AYN;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Information", 8 | "Microsoft": "Warning", 9 | "Microsoft.Hosting.Lifetime": "Information" 10 | } 11 | }, 12 | "Stripe": { 13 | "SecretKey": "sk_test_51JC369DjgxsARjFq3ShjvFTDUp2USjseDloHEiIvpQlxdKns6udUNa7GsqyYKGvc87kjWbm8svxDQhYaa4y5sXLb009CHToeUX", 14 | "PublishableKey": "pk_test_51JC369DjgxsARjFqEYyTTQYKHthtU3IFY0xfHpGRdLL0BVlvRMmBrrU488pdLUKjHzHvHkHTJoZzKFi3ucsj4wwp00d7D0oPEk" 15 | }, 16 | "Cloudinary": { 17 | "CloudName": "da6tcqesv", 18 | "ApiKey": "159193426587866", 19 | "ApiSecret": "Sc0fny-LbApUbQs4b0Sjh9cgRaY" 20 | }, 21 | "Sendgrid": { 22 | "ApiKey": "" 23 | }, 24 | "AllowedHosts": "*" 25 | } 26 | -------------------------------------------------------------------------------- /stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "layoutRules": { 5 | "newlineAtEndOfFile": "require" 6 | }, 7 | "namingRules": { 8 | "allowCommonHungarianPrefixes": true, 9 | "allowedHungarianPrefixes": [ "db", "at", "or", "up", "it", "un", "x", "y", "id", "ip", "bg", "ad", "em" ] 10 | }, 11 | "documentationRules": { 12 | "companyName": "AYN", 13 | "copyrightText": "Copyright (c) {companyName}. All Rights Reserved.", 14 | "documentInterfaces": false, 15 | "documentInternalElements": false 16 | }, 17 | "orderingRules": { 18 | "usingDirectivesPlacement": "outsideNamespace", 19 | "systemUsingDirectivesFirst": true, 20 | "blankLinesBetweenUsingGroups": "require" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Comment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | using AYN.Data.Common.Models; 6 | 7 | using static AYN.Common.AttributeConstraints; 8 | 9 | namespace AYN.Data.Models; 10 | 11 | public class Comment : BaseDeletableModel 12 | { 13 | public Comment() 14 | { 15 | this.Id = Guid.NewGuid().ToString(); 16 | } 17 | 18 | [Required] 19 | public string AddedByUserId { get; set; } 20 | 21 | public virtual ApplicationUser AddedByUser { get; set; } 22 | 23 | [Required] 24 | public string AdId { get; set; } 25 | 26 | public virtual Ad Ad { get; set; } 27 | 28 | [Required] 29 | [MaxLength(CommentContentMaxLength)] 30 | public string Content { get; set; } 31 | 32 | public virtual ICollection CommentVotes { get; set; } 33 | = new HashSet(); 34 | } 35 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_typography.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Raleway:300,400,500,600,700'); 2 | 3 | body { 4 | font-weight: $font-weight-base; 5 | font-family: $font-family-sans-serif; 6 | color: $grey-800; 7 | } 8 | 9 | b { 10 | font-weight: 700; 11 | } 12 | 13 | h1,h2,h3,h4,h5,h6{ 14 | font-weight: $headings-font-weight; 15 | color: $dark; 16 | } 17 | 18 | .display-1, 19 | .display-2, 20 | .display-3, 21 | .display-4, 22 | .display-5, 23 | .display-6 { 24 | font-weight: 800; 25 | } 26 | 27 | @each $color,$value in $theme-colors { 28 | .text-#{$color} { 29 | @include text-color($value); 30 | } 31 | } 32 | 33 | //blockquote 34 | .blockquote { 35 | border-left: 0.2rem solid $primary; 36 | font-size: $blockquote-font-size; 37 | padding-left: 1.5rem; 38 | } 39 | 40 | .icon { 41 | position: relative; 42 | top: .2em; 43 | } 44 | 45 | .big-icon { 46 | font-size: 3rem; 47 | } -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Users/Followers.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Users.ListFollowersViewModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Followers"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 |
12 | @foreach (var follower in this.Model.Followers) 13 | { 14 |
15 |
16 | 17 |
18 |

@follower.FollowerFirstName @follower.FollowerLastName

19 |
20 |
21 |
22 | } 23 |
24 | 25 | -------------------------------------------------------------------------------- /Data/AYN.Data/DbQueryRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Data.Common; 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace AYN.Data; 9 | 10 | public class DbQueryRunner : IDbQueryRunner 11 | { 12 | public DbQueryRunner(ApplicationDbContext context) 13 | { 14 | this.Context = context ?? throw new ArgumentNullException(nameof(context)); 15 | } 16 | 17 | public ApplicationDbContext Context { get; set; } 18 | 19 | public Task RunQueryAsync(string query, params object[] parameters) 20 | => this.Context.Database.ExecuteSqlRawAsync(query, parameters); 21 | 22 | public void Dispose() 23 | { 24 | this.Dispose(true); 25 | GC.SuppressFinalize(this); 26 | } 27 | 28 | protected virtual void Dispose(bool disposing) 29 | { 30 | if (disposing) 31 | { 32 | this.Context?.Dispose(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Data/AYN.Data/DesignTimeDbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Design; 5 | using Microsoft.Extensions.Configuration; 6 | 7 | namespace AYN.Data; 8 | 9 | public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory 10 | { 11 | public ApplicationDbContext CreateDbContext(string[] args) 12 | { 13 | var configuration = new ConfigurationBuilder() 14 | .SetBasePath(Directory.GetCurrentDirectory()) 15 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 16 | .Build(); 17 | 18 | var builder = new DbContextOptionsBuilder(); 19 | var connectionString = configuration.GetConnectionString("DefaultConnection"); 20 | 21 | builder.UseSqlServer(connectionString); 22 | return new ApplicationDbContext(builder.Options); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetSuggestionPeopleViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Users; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.ViewComponents; 8 | 9 | public class GetSuggestionPeopleViewComponent : ViewComponent 10 | { 11 | private readonly IUsersService usersService; 12 | 13 | public GetSuggestionPeopleViewComponent( 14 | IUsersService usersService) 15 | { 16 | this.usersService = usersService; 17 | } 18 | 19 | public async Task InvokeAsync(string currentUserId, string openedUserId) 20 | { 21 | var viewModel = new ListSuggestionPeopleViewModel 22 | { 23 | SuggestionPeople = await this.usersService.GetSuggestionPeople(currentUserId, openedUserId), 24 | }; 25 | 26 | return this.View(viewModel); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Users/Followees.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Users.ListFolloweesViewModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Followees"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 | 12 |
13 | @foreach (var followee in this.Model.Followees) 14 | { 15 |
16 |
17 | 18 |
19 |

@followee.FolloweeFirstName @followee.FolloweeLastName

20 |
21 |
22 |
23 | } 24 |
25 | 26 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetUserRecentAdViewsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Ads; 5 | using AYN.Web.ViewModels.Users; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.ViewComponents; 9 | 10 | public class GetUserRecentAdViewsViewComponent : ViewComponent 11 | { 12 | private readonly IUserLatestAdViewsService userLatestAdViewsService; 13 | 14 | public GetUserRecentAdViewsViewComponent( 15 | IUserLatestAdViewsService userLatestAdViewsService) 16 | { 17 | this.userLatestAdViewsService = userLatestAdViewsService; 18 | } 19 | 20 | public async Task InvokeAsync(string userId) 21 | { 22 | var viewModel = new ListUserAdsViewModel 23 | { 24 | Ads = await this.userLatestAdViewsService.GetUserLatestAdViews(userId), 25 | }; 26 | 27 | return this.View(viewModel); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/Post.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | 6 | using static AYN.Common.AttributeConstraints; 7 | 8 | namespace AYN.Data.Models; 9 | 10 | public class Post : BaseDeletableModel 11 | { 12 | [Required] 13 | [MaxLength(PostTitleMaxLength)] 14 | public string Title { get; set; } 15 | 16 | [Required] 17 | [MaxLength(PostContentMaxLength)] 18 | public string Content { get; set; } 19 | 20 | [Required] 21 | public string AddedByUserId { get; set; } 22 | 23 | public virtual ApplicationUser ApplicationUser { get; set; } 24 | 25 | public virtual ICollection Tags { get; set; } 26 | = new HashSet(); 27 | 28 | public virtual ICollection PostVotes { get; set; } 29 | = new HashSet(); 30 | 31 | public virtual ICollection PostReacts { get; set; } 32 | = new HashSet(); 33 | } 34 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/PagingViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AYN.Web.ViewModels; 4 | 5 | public class PagingViewModel 6 | { 7 | public int PageNumber { get; set; } 8 | 9 | public bool HasPreviousPage 10 | => this.PageNumber > 1; 11 | 12 | public bool HasNextPage 13 | => this.PageNumber < this.PagesCount; 14 | 15 | public int PreviousPageNumber 16 | => this.PageNumber - 1; 17 | 18 | public int NextPageNumber 19 | => this.PageNumber + 1; 20 | 21 | public int Count { get; set; } 22 | 23 | public int ItemsPerPage { get; set; } 24 | 25 | public int PagesCount 26 | => (int)Math.Ceiling((double)this.Count / this.ItemsPerPage); 27 | 28 | public string Search { get; set; } 29 | 30 | public string Letter { get; set; } 31 | 32 | public string OrderBy { get; set; } 33 | 34 | public string Town { get; set; } 35 | 36 | public int? CategoryId { get; set; } 37 | 38 | public int PagedId { get; set; } 39 | } 40 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (this.Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @this.Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to Development environment will display more detailed information about the error that occurred. 20 |

21 |

22 | The Development environment shouldn't be enabled for deployed applications. 23 | It can result in displaying sensitive information from exceptions to end users. 24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 25 | and restarting the app. 26 |

27 | -------------------------------------------------------------------------------- /Data/AYN.Data.Models/AYN.Data.Models.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Comments/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Comments.EditCommentInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Edit Comment"; 5 | } 6 | 7 | 8 |
9 |
10 |
11 |
12 |
13 | 14 | 15 |
16 |
17 | 20 |
21 | 22 | 23 |
24 |
25 | 26 | 27 |
28 |
-------------------------------------------------------------------------------- /Web/AYN.Web/Controllers/PostReactsController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.Infrastructure.Extensions; 5 | using AYN.Web.ViewModels.PostReacts; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.Controllers; 9 | 10 | [ApiController] 11 | [Route("api/[controller]")] 12 | public class PostReactsController : BaseController 13 | { 14 | private readonly IPostReactsService postReactsService; 15 | 16 | public PostReactsController(IPostReactsService postReactsService) 17 | => this.postReactsService = postReactsService; 18 | 19 | [HttpPost] 20 | public async Task> Post(PostReactInputModel input) 21 | { 22 | await this.postReactsService.SetReactAsync(input.PostId, this.User.GetId(), input.ReactValue); 23 | var totalReacts = this.postReactsService.GetTotalReacts(input.PostId); 24 | 25 | return new PostReactResponseModel { TotalReacts = totalReacts }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/_popovers.scss: -------------------------------------------------------------------------------- 1 | .popover { 2 | background-color: $bg-warning; 3 | border: none; 4 | 5 | .popover-body { 6 | color: $white; 7 | } 8 | } 9 | 10 | .bs-popover-auto[x-placement^="top"], 11 | .bs-popover-top { 12 | .arrow::after{ 13 | border-top-color: $bg-warning; 14 | } 15 | .arrow::before { 16 | border-top-color: transparent 17 | } 18 | } 19 | 20 | .bs-popover-auto[x-placement^="bottom"], 21 | .bs-popover-bottom { 22 | .arrow::after{ 23 | border-bottom-color: $bg-warning; 24 | } 25 | .arrow::before { 26 | border-bottom-color: transparent 27 | } 28 | } 29 | 30 | .bs-popover-auto[x-placement^="left"], 31 | .bs-popover-left { 32 | .arrow::after{ 33 | border-left-color: $bg-warning; 34 | } 35 | .arrow::before { 36 | border-left-color: transparent 37 | } 38 | } 39 | 40 | .bs-popover-auto[x-placement^="right"], 41 | .bs-popover-right { 42 | .arrow::after{ 43 | border-right-color: $bg-warning; 44 | } 45 | .arrow::before { 46 | border-right-color: transparent 47 | } 48 | } -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Emojis/All.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Emojis.ListEmojiViewModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "All Emojis"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 |
11 | 12 |
13 |
14 |
15 |
16 | @foreach (var emoji in this.Model.Emojis) 17 | { 18 | @emoji.Image 19 | } 20 |
21 |
-------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Emojis/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Emojis.CreateEmojiInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Add Emoji"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 |
20 | 23 |
24 | 25 |
26 |
27 | 28 | 29 |
30 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Users/Ban.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Users.BanUserInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Ban User"; 5 | } 6 |
7 |

Ban User

8 |
9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 |
17 |
18 | 21 |
22 | 23 |
24 |
25 | 26 | 27 |
28 |
-------------------------------------------------------------------------------- /Data/AYN.Data.Models/Report.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | using AYN.Data.Common.Models; 5 | using AYN.Data.Models.Enumerations; 6 | 7 | using static AYN.Common.AttributeConstraints; 8 | 9 | namespace AYN.Data.Models; 10 | 11 | public class Report : BaseDeletableModel 12 | { 13 | public Report() 14 | { 15 | this.Id = Guid.NewGuid().ToString(); 16 | } 17 | 18 | [Required] 19 | [MaxLength(ReportContentMaxLength)] 20 | public string Description { get; set; } 21 | 22 | [Required] 23 | public ReportType ReportType { get; set; } 24 | 25 | [Required] 26 | public string ReportingUserId { get; set; } 27 | 28 | public virtual ApplicationUser ReportingUser { get; set; } 29 | 30 | [Required] 31 | public string ReportedUserId { get; set; } 32 | 33 | public virtual ApplicationUser ReportedUser { get; set; } 34 | 35 | [Required] 36 | public string ReportedAdId { get; set; } 37 | 38 | public virtual Ad ReportedAd { get; set; } 39 | } 40 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Categories/AddSubCategory.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Categories.AddSubCategoryInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Add subCategory"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 |
20 | 23 |
24 | 25 |
26 |
27 | 28 | 29 |
-------------------------------------------------------------------------------- /Data/AYN.Data/Configurations/ApplicationUserConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace AYN.Data.Configurations; 6 | 7 | public class ApplicationUserConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder applicationUser) 10 | { 11 | applicationUser.HasMany(e => e.Claims) 12 | .WithOne() 13 | .HasForeignKey(e => e.UserId) 14 | .IsRequired() 15 | .OnDelete(DeleteBehavior.Restrict); 16 | 17 | applicationUser.HasMany(e => e.Logins) 18 | .WithOne() 19 | .HasForeignKey(e => e.UserId) 20 | .IsRequired() 21 | .OnDelete(DeleteBehavior.Restrict); 22 | 23 | applicationUser.HasMany(e => e.Roles) 24 | .WithOne() 25 | .HasForeignKey(e => e.UserId) 26 | .IsRequired() 27 | .OnDelete(DeleteBehavior.Restrict); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetHomePageStatisticsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Home; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.ViewComponents; 8 | 9 | public class GetHomePageStatisticsViewComponent : ViewComponent 10 | { 11 | private readonly IAdsService adsService; 12 | private readonly IUsersService usersService; 13 | 14 | public GetHomePageStatisticsViewComponent( 15 | IAdsService adsService, 16 | IUsersService usersService) 17 | { 18 | this.adsService = adsService; 19 | this.usersService = usersService; 20 | } 21 | 22 | public Task InvokeAsync() 23 | { 24 | var viewModel = new IndexPageStatisticsViewModel 25 | { 26 | AdsCount = this.adsService.GetCounts().Item2, 27 | UsersCount = this.usersService.GetCounts().Item3, 28 | }; 29 | 30 | return Task.FromResult(this.View(viewModel)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/lib/tinymce/skins/content/default/content.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table td,table th{border:1px solid #ccc;padding:.4rem}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem} 8 | /*# sourceMappingURL=content.min.css.map */ 9 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Ads/Promote.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Ads.PromoteAdInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Promote Ad"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 |
20 | 23 |
24 | 25 |
26 |
27 | 28 | 29 |
30 |
-------------------------------------------------------------------------------- /Services/AYN.Services.Data/Implementations/FeedbackService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Data.Common.Repositories; 4 | using AYN.Data.Models; 5 | using AYN.Services.Data.Interfaces; 6 | using AYN.Web.ViewModels.Feedback; 7 | 8 | namespace AYN.Services.Data.Implementations; 9 | 10 | public class FeedbackService : IFeedbackService 11 | { 12 | private readonly IDeletableEntityRepository feedbackRepository; 13 | 14 | public FeedbackService( 15 | IDeletableEntityRepository feedbackRepository) 16 | { 17 | this.feedbackRepository = feedbackRepository; 18 | } 19 | 20 | public async Task CreateAsync(CreateFeedbackInputModel input, string userId) 21 | { 22 | var feedback = new Feedback 23 | { 24 | Email = input.Email, 25 | AddedByUserId = userId, 26 | Content = input.Content, 27 | Title = input.Title, 28 | }; 29 | 30 | await this.feedbackRepository.AddAsync(feedback); 31 | await this.feedbackRepository.SaveChangesAsync(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AYN - All you need. 2 | ASP.NET Core Application for online web trading between people. 3 | 4 | 5 | # Project Template: 6 | * [Niki Kostov's Template](https://github.com/NikolayIT/ASP.NET-Core-Template) 7 | 8 | # 🛠 Technologies Used: 9 | * [ASP.NET Core](https://github.com/dotnet/aspnetcore) 10 | * [Entity Framework Core](https://github.com/dotnet/efcore) 11 | * [SignalR](https://github.com/SignalR/SignalR) 12 | * [AutoMapper](https://github.com/AutoMapper/AutoMapper) 13 | * [SendGrid](https://github.com/sendgrid) 14 | * [Cloudinary](https://github.com/cloudinary/CloudinaryDotNet) 15 | * [AngleSharp](https://github.com/AngleSharp/AngleSharp) 16 | * [Stripe](https://github.com/stripe/stripe-dotnet) 17 | * [HangFire](https://github.com/HangfireIO/Hangfire) 18 | * [HtmlSanitizer](https://github.com/mganss/HtmlSanitizer) 19 | * [Bootstrap](https://github.com/twbs/bootstrap) 20 | * [jQuery](https://github.com/jquery/jquery) 21 | * [TinyMCE](https://github.com/tinymce/) 22 | * [nUnit](https://github.com/nunit) 23 | * [Moq](https://github.com/moq/moq) 24 | 25 | Give it a star if you like it :)). 26 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/ISubCategoriesService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | 5 | using AYN.Data.Models; 6 | using AYN.Web.ViewModels.Administration.Categories; 7 | using AYN.Web.ViewModels.Administration.SubCategories; 8 | 9 | namespace AYN.Services.Data.Interfaces; 10 | 11 | public interface ISubCategoriesService 12 | { 13 | Task CreateAsync(AddSubCategoryInputModel input, int categoryId); 14 | 15 | IQueryable GetAllByCategoryId(int categoryId); 16 | 17 | Task>> GetAllAsKeyValuePairsAsync(); 18 | 19 | Task>> GetAllByCategoryIdAsKeyValuePairsAsync(int categoryId); 20 | 21 | Task GetByIdAsync(int id); 22 | 23 | SubCategory Get(int id); 24 | 25 | Task DeleteAsync(int id); 26 | 27 | Task UnDeleteAsync(int id); 28 | 29 | Task EditAsync(EditSubCategoryInputModel input); 30 | 31 | bool IsSubCategoryExisting(string subCategoryName); 32 | 33 | bool IsSubCategoryExisting(int id); 34 | } 35 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/SubCategories/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.SubCategories.EditSubCategoryInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Edit SubCategory"; 5 | } 6 | 7 |
8 |

@this.ViewData["Title"]

9 |
10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 | 18 | 19 |
20 |
21 | 24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 |
-------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetMoreAdsFromUserViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Services.Data.Interfaces; 5 | using AYN.Web.ViewModels.Ads; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.ViewComponents; 9 | 10 | public class GetMoreAdsFromUserViewComponent : ViewComponent 11 | { 12 | private readonly IAdsService adsService; 13 | 14 | public GetMoreAdsFromUserViewComponent( 15 | IAdsService adsService) 16 | { 17 | this.adsService = adsService; 18 | } 19 | 20 | public async Task InvokeAsync(string townName, int categoryId, int subCategoryId, string currentAdId) 21 | { 22 | var userId = this.UserClaimsPrincipal.FindFirst(ClaimTypes.NameIdentifier)?.Value; 23 | 24 | var viewModel = new ListMoreAdsByUserViewModel 25 | { 26 | Ads = await this.adsService.GetMoreFromUserAds(townName, categoryId, subCategoryId, userId, currentAdId), 27 | }; 28 | 29 | return this.View(viewModel); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Template Name: Daily Shop 3 | Author : MarkUps.io 4 | Author URI: http://www.markups.io/ 5 | Version: 1.0 6 | 7 | */ 8 | 9 | 10 | /* BASE - Base tyles, Variables, Mixins, etc. */ 11 | 12 | 13 | @import 'base/_variables.scss'; 14 | @import 'base/_mixins.scss'; 15 | @import 'base/_base.scss'; 16 | 17 | /* MODULES - Individual site components */ 18 | 19 | @import 'modules/_typography.scss'; 20 | @import 'modules/_buttons.scss'; 21 | 22 | 23 | 24 | /* LAYOUTS - Page layout styles */ 25 | 26 | 27 | 28 | /*================== 29 | HEADER SECTION 30 | ====================*/ 31 | 32 | @import 'layouts/_header.scss'; 33 | 34 | /*================== 35 | NAVBAR SECTION 36 | ====================*/ 37 | 38 | @import 'layouts/_nav.scss'; 39 | 40 | /* ALL SECTION */ 41 | 42 | @import 'modules/_sections.scss'; 43 | 44 | /*================== 45 | FOOTER SECTION 46 | ====================*/ 47 | 48 | @import 'layouts/_footer.scss'; 49 | 50 | /*================== 51 | RESPONSIVE DESIGN 52 | ====================*/ 53 | 54 | @import 'modules/_responsive.scss'; 55 | -------------------------------------------------------------------------------- /Web/AYN.Web/ViewComponents/GetUserPostsViewComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Services.Data.Interfaces; 5 | using AYN.Web.ViewModels.Posts; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.ViewComponents; 9 | 10 | public class GetUserPostsViewComponent : ViewComponent 11 | { 12 | private readonly IPostsService postsService; 13 | 14 | public GetUserPostsViewComponent( 15 | IPostsService postsService) 16 | { 17 | this.postsService = postsService; 18 | } 19 | 20 | public async Task InvokeAsync(string userId, int id) 21 | { 22 | var posts = await this.postsService.GetUserAllPostsAsync(userId); 23 | 24 | var viewModel = new ListUserPostsViewModel 25 | { 26 | UserPosts = posts.Skip((id - 1) * 6).Take(6), 27 | Count = this.postsService.GetCount(userId), 28 | ItemsPerPage = 6, 29 | PageNumber = id, 30 | PagedId = id, 31 | }; 32 | 33 | return this.View(viewModel); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/ICategoriesService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | using AYN.Web.ViewModels.Administration.Categories; 7 | 8 | using EditCategoryInputModel = AYN.Web.ViewModels.Administration.Categories.EditCategoryInputModel; 9 | 10 | namespace AYN.Services.Data.Interfaces; 11 | 12 | public interface ICategoriesService 13 | { 14 | Task CreateAsync(CreateCategoryInputModel input); 15 | 16 | IQueryable GetAll(); 17 | 18 | Task> GetAllWithDeletedAsync(); 19 | 20 | Task>> GetAllAsKeyValuePairsAsync(); 21 | 22 | Task GetByIdAsync(int categoryId); 23 | 24 | Task UpdateAsync(EditCategoryInputModel input, int categoryId, string imagePath); 25 | 26 | Task DeleteAsync(int id); 27 | 28 | Task UnDeleteAsync(int id); 29 | 30 | Tuple GetCounts(); 31 | 32 | int GetTotalCount(); 33 | 34 | bool IsExisting(int categoryId); 35 | 36 | bool IsCategoryContainsGivenSubCategory(int categoryId, int subCategoryId); 37 | } 38 | -------------------------------------------------------------------------------- /Services/AYN.Services.Mapping/QueryableMappingExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | 5 | using AutoMapper.QueryableExtensions; 6 | 7 | namespace AYN.Services.Mapping; 8 | 9 | public static class QueryableMappingExtensions 10 | { 11 | public static IQueryable To( 12 | this IQueryable source, 13 | params Expression>[] membersToExpand) 14 | { 15 | if (source == null) 16 | { 17 | throw new ArgumentNullException(nameof(source)); 18 | } 19 | 20 | return source.ProjectTo(AutoMapperConfig.MapperInstance.ConfigurationProvider, null, membersToExpand); 21 | } 22 | 23 | public static IQueryable To( 24 | this IQueryable source, 25 | object parameters) 26 | { 27 | if (source == null) 28 | { 29 | throw new ArgumentNullException(nameof(source)); 30 | } 31 | 32 | return source.ProjectTo(AutoMapperConfig.MapperInstance.ConfigurationProvider, parameters); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Georgi Delchev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Implementations/UserLatestAdViewsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | 5 | using AYN.Data.Common.Repositories; 6 | using AYN.Data.Models; 7 | using AYN.Services.Data.Interfaces; 8 | using AYN.Services.Mapping; 9 | using Microsoft.EntityFrameworkCore; 10 | 11 | namespace AYN.Services.Data.Implementations; 12 | 13 | public class UserLatestAdViewsService : IUserLatestAdViewsService 14 | { 15 | private readonly IDeletableEntityRepository userAdViewsRepository; 16 | 17 | public UserLatestAdViewsService( 18 | IDeletableEntityRepository userAdViewsRepository) 19 | { 20 | this.userAdViewsRepository = userAdViewsRepository; 21 | } 22 | 23 | public async Task> GetUserLatestAdViews(string userId) 24 | => await this.userAdViewsRepository 25 | .All() 26 | .Where(uav => uav.UserId == userId) 27 | .OrderByDescending(uav => uav.CreatedOn) 28 | .Take(12) 29 | .Select(uav => uav.Ad) 30 | .To() 31 | .ToListAsync(); 32 | } 33 | -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Implementations/UserAdsViewsService.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Data.Common.Repositories; 5 | using AYN.Data.Models; 6 | using AYN.Services.Data.Interfaces; 7 | 8 | namespace AYN.Services.Data.Implementations; 9 | 10 | public class UserAdsViewsService : IUserAdsViewsService 11 | { 12 | private readonly IDeletableEntityRepository userAdsViewsRepository; 13 | 14 | public UserAdsViewsService( 15 | IDeletableEntityRepository userAdsViewsRepository) 16 | { 17 | this.userAdsViewsRepository = userAdsViewsRepository; 18 | } 19 | 20 | public async Task CreateAsync(string userId, string adId) 21 | { 22 | if (this.userAdsViewsRepository.All().Any(uav => uav.UserId == userId && uav.AdId == adId)) 23 | { 24 | return; 25 | } 26 | 27 | var userAdView = new UserAdView 28 | { 29 | AdId = adId, 30 | UserId = userId, 31 | }; 32 | 33 | await this.userAdsViewsRepository.AddAsync(userAdView); 34 | await this.userAdsViewsRepository.SaveChangesAsync(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/_CookieConsentPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Http.Features 2 | 3 | @{ 4 | var consentFeature = this.Context.Features.Get(); 5 | var showBanner = !consentFeature?.CanTrack ?? false; 6 | var cookieString = consentFeature?.CreateConsentCookie(); 7 | } 8 | 9 | @if (showBanner) 10 | { 11 | 17 | 25 | } 26 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Ads/WishlistAdsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | using AutoMapper; 5 | using AYN.Data.Models; 6 | using AYN.Services.Mapping; 7 | 8 | using static AYN.Common.AttributeConstraints; 9 | 10 | namespace AYN.Web.ViewModels.Ads; 11 | 12 | public class WishlistAdsViewModel : IMapFrom, IHaveCustomMappings 13 | { 14 | public string Id { get; set; } 15 | 16 | public string Name { get; set; } 17 | 18 | public string Description { get; set; } 19 | 20 | public string ShortDescription 21 | => this.Description.Substring(0, DescriptionMinLength); 22 | 23 | public string ImageUrl { get; set; } 24 | 25 | public decimal Price { get; set; } 26 | 27 | public bool IsPromoted { get; set; } 28 | 29 | public DateTime? PromotedUntil { get; set; } 30 | 31 | public string AddedByUserId { get; set; } 32 | 33 | public string AddedByUserUsername { get; set; } 34 | 35 | public void CreateMappings(IProfileExpression configuration) 36 | { 37 | configuration.CreateMap() 38 | .ForMember(m => m.ImageUrl, opt => opt.MapFrom(o => o.Images.FirstOrDefault().ImageUrl)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210717155101_RenameUserAvatarAndThumbnailFields.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class RenameUserAvatarAndThumbnailFields : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.RenameColumn( 10 | name: "ThumbnailExtension", 11 | table: "AspNetUsers", 12 | newName: "ThumbnailImageUrl"); 13 | 14 | migrationBuilder.RenameColumn( 15 | name: "AvatarExtension", 16 | table: "AspNetUsers", 17 | newName: "AvatarImageUrl"); 18 | } 19 | 20 | protected override void Down(MigrationBuilder migrationBuilder) 21 | { 22 | migrationBuilder.RenameColumn( 23 | name: "ThumbnailImageUrl", 24 | table: "AspNetUsers", 25 | newName: "ThumbnailExtension"); 26 | 27 | migrationBuilder.RenameColumn( 28 | name: "AvatarImageUrl", 29 | table: "AspNetUsers", 30 | newName: "AvatarExtension"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Comments/CommentViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | using AutoMapper; 5 | using AYN.Data.Models; 6 | using AYN.Data.Models.Enumerations; 7 | using AYN.Services.Mapping; 8 | 9 | namespace AYN.Web.ViewModels.Comments; 10 | 11 | public class CommentViewModel : IMapFrom, IHaveCustomMappings 12 | { 13 | public string Id { get; set; } 14 | 15 | public string Content { get; set; } 16 | 17 | public DateTime CreatedOn { get; set; } 18 | 19 | public string AddedByUserUsername { get; set; } 20 | 21 | public string AddedByUserId { get; set; } 22 | 23 | public string AddedByUserAvatarImageUrl { get; set; } 24 | 25 | public int CommentUpVotesCount { get; set; } 26 | 27 | public int CommentDownVotesCount { get; set; } 28 | 29 | public void CreateMappings(IProfileExpression configuration) 30 | { 31 | configuration.CreateMap() 32 | .ForMember(m => m.CommentUpVotesCount, opt => opt.MapFrom(o => o.CommentVotes.Count(a => a.Value == CommentVoteValue.Up))) 33 | .ForMember(m => m.CommentDownVotesCount, opt => opt.MapFrom(o => o.CommentVotes.Count(a => a.Value == CommentVoteValue.Down))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Components/GetSuggestionPeople/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Users.ListSuggestionPeopleViewModel 2 | 3 |
4 | 27 |
28 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/js/sequence-theme.modern-slide-in.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Theme Name: Modern Slide In 3 | * Version: 2.0.0 4 | * Theme URL: http://sequencejs.com/themes/modern-slide-in/ 5 | * 6 | * A minimalist theme for showcasing products 7 | * 8 | * This theme is powered by Sequence.js - The 9 | * responsive CSS animation framework for creating unique sliders, 10 | * presentations, banners, and other step-based applications. 11 | * 12 | * Author: Ian Lunn 13 | * Author URL: http://ianlunn.co.uk/ 14 | * 15 | * Theme License: http://sequencejs.com/licenses/#free-theme 16 | * Sequence.js Licenses: http://sequencejs.com/licenses/ 17 | * 18 | * Copyright © 2015 Ian Lunn Design Limited unless otherwise stated. 19 | */ 20 | 21 | // Get the Sequence element 22 | var sequenceElement = document.getElementById("sequence"); 23 | 24 | // Place your Sequence options here to override defaults 25 | // See: http://sequencejs.com/documentation/#options 26 | var options = { 27 | animateCanvas: false, 28 | phaseThreshold: false, 29 | preloader: true, 30 | reverseWhenNavigatingBackwards: true 31 | } 32 | 33 | // Launch Sequence on the element, and with the options we specified above 34 | var mySequence = sequence(sequenceElement, options); 35 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210628211541_IncreaseNotificationTextMaxLength.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class IncreaseNotificationTextMaxLength : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AlterColumn( 10 | name: "Text", 11 | table: "Notifications", 12 | type: "nvarchar(200)", 13 | maxLength: 200, 14 | nullable: false, 15 | oldClrType: typeof(string), 16 | oldType: "nvarchar(50)", 17 | oldMaxLength: 50); 18 | } 19 | 20 | protected override void Down(MigrationBuilder migrationBuilder) 21 | { 22 | migrationBuilder.AlterColumn( 23 | name: "Text", 24 | table: "Notifications", 25 | type: "nvarchar(50)", 26 | maxLength: 50, 27 | nullable: false, 28 | oldClrType: typeof(string), 29 | oldType: "nvarchar(200)", 30 | oldMaxLength: 200); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210819202135_IncreaseAdDescriptionCharsCount.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class IncreaseAdDescriptionCharsCount : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AlterColumn( 10 | name: "Description", 11 | table: "Ads", 12 | type: "nvarchar(max)", 13 | maxLength: 5000, 14 | nullable: false, 15 | oldClrType: typeof(string), 16 | oldType: "nvarchar(1000)", 17 | oldMaxLength: 1000); 18 | } 19 | 20 | protected override void Down(MigrationBuilder migrationBuilder) 21 | { 22 | migrationBuilder.AlterColumn( 23 | name: "Description", 24 | table: "Ads", 25 | type: "nvarchar(1000)", 26 | maxLength: 1000, 27 | nullable: false, 28 | oldClrType: typeof(string), 29 | oldType: "nvarchar(max)", 30 | oldMaxLength: 5000); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Data/AYN.Data/Seeding/Seeders/RolesSeeder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | 5 | using AYN.Common; 6 | using AYN.Data.Models; 7 | using AYN.Data.Seeding.Interfaces; 8 | using Microsoft.AspNetCore.Identity; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace AYN.Data.Seeding.Seeders; 12 | 13 | internal class RolesSeeder : ISeeder 14 | { 15 | public async Task SeedAsync(ApplicationDbContext dbContext, IServiceProvider serviceProvider) 16 | { 17 | var roleManager = serviceProvider.GetRequiredService>(); 18 | 19 | await SeedRoleAsync(roleManager, GlobalConstants.AdministratorRoleName); 20 | } 21 | 22 | private static async Task SeedRoleAsync(RoleManager roleManager, string roleName) 23 | { 24 | var role = await roleManager.FindByNameAsync(roleName); 25 | 26 | if (role == null) 27 | { 28 | var result = await roleManager.CreateAsync(new ApplicationRole(roleName)); 29 | 30 | if (!result.Succeeded) 31 | { 32 | throw new Exception(string.Join(Environment.NewLine, result.Errors.Select(e => e.Description))); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/lib/tinymce/plugins/code/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | * 7 | * Version: 5.2.0 (2020-02-13) 8 | */ 9 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(e,n){e.focus(),e.undoManager.transact(function(){e.setContent(n)}),e.selection.setCursorLocation(),e.nodeChanged()},o=function(e){return e.getContent({source_view:!0})},n=function(n){var e=o(n);n.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:e},onSubmit:function(e){t(n,e.getData().code),e.close()}})},c=function(e){e.addCommand("mceCodeEditor",function(){n(e)})},i=function(e){e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:function(){return n(e)}}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:function(){return n(e)}})};!function u(){e.add("code",function(e){return c(e),i(e),{}})}()}(); -------------------------------------------------------------------------------- /Services/AYN.Services.RecurringJobs/UnpromoteExpiredAdsRecurringJob.cs: -------------------------------------------------------------------------------- 1 | using AYN.Data; 2 | using Hangfire; 3 | using Hangfire.Console; 4 | using Hangfire.Server; 5 | 6 | namespace AYN.Services.RecurringJobs; 7 | 8 | public class UnpromoteExpiredAdsRecurringJob 9 | { 10 | private readonly ApplicationDbContext dbContext; 11 | 12 | public UnpromoteExpiredAdsRecurringJob( 13 | ApplicationDbContext dbContext) 14 | { 15 | this.dbContext = dbContext; 16 | } 17 | 18 | [AutomaticRetry(Attempts = 2)] 19 | public async Task StartWorking(PerformContext context) 20 | { 21 | var expiredAds = this.dbContext 22 | .Ads 23 | .Where(a => a.IsPromoted && 24 | a.PromotedUntil <= DateTime.Now) 25 | .ToList(); 26 | 27 | foreach (var expiredAd in expiredAds.WithProgress(context.WriteProgressBar())) 28 | { 29 | expiredAd.IsPromoted = false; 30 | expiredAd.PromotedOn = null; 31 | expiredAd.PromotedUntil = null; 32 | 33 | this.dbContext.Update(expiredAd); 34 | await this.dbContext.SaveChangesAsync(); 35 | 36 | context.WriteLine($"Successfully un-promoted ad with title: {expiredAd.Name}"); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Tests/AYN.Web.Tests/SeleniumServerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | using Microsoft.AspNetCore; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.AspNetCore.Hosting.Server.Features; 7 | using Microsoft.AspNetCore.Mvc.Testing; 8 | using Microsoft.AspNetCore.TestHost; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace AYN.Web.Tests; 12 | 13 | public sealed class SeleniumServerFactory : WebApplicationFactory 14 | where TStartup : class 15 | { 16 | public SeleniumServerFactory() 17 | { 18 | this.ClientOptions.BaseAddress = new Uri("https://localhost"); 19 | 20 | var host = WebHost.CreateDefaultBuilder(Array.Empty()).UseStartup().Build(); 21 | 22 | host.Start(); 23 | 24 | this.RootUri = host.ServerFeatures.Get().Addresses.LastOrDefault(); 25 | 26 | var testServer = new TestServer(new WebHostBuilder().UseStartup()); 27 | } 28 | 29 | public string RootUri { get; set; } 30 | 31 | public class FakeStartup 32 | { 33 | public void ConfigureServices(IServiceCollection services) 34 | { 35 | } 36 | 37 | public void Configure() 38 | { 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Tests/AYN.Services.Data.Tests/AYN.Services.Data.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | latest 6 | 7 | 8 | 9 | ..\..\Rules.ruleset 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | runtime; build; native; contentfiles; analyzers 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml: -------------------------------------------------------------------------------- 1 | @inject SignInManager SignInManager 2 | @{ 3 | var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any(); 4 | } 5 | 16 | -------------------------------------------------------------------------------- /Tests/AYN.Web.Tests/WebTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Threading.Tasks; 3 | 4 | using Microsoft.AspNetCore.Mvc.Testing; 5 | 6 | using Xunit; 7 | 8 | namespace AYN.Web.Tests; 9 | 10 | public class WebTests : IClassFixture> 11 | { 12 | private readonly WebApplicationFactory server; 13 | 14 | public WebTests(WebApplicationFactory server) 15 | { 16 | this.server = server; 17 | } 18 | 19 | [Fact(Skip = "Example test. Disabled for CI.")] 20 | public async Task IndexPageShouldReturnStatusCode200WithTitle() 21 | { 22 | var client = this.server.CreateClient(); 23 | var response = await client.GetAsync("/"); 24 | 25 | response.EnsureSuccessStatusCode(); 26 | 27 | var responseContent = await response.Content.ReadAsStringAsync(); 28 | 29 | Assert.Contains("", responseContent); 30 | } 31 | 32 | [Fact(Skip = "Example test. Disabled for CI.")] 33 | public async Task AccountManagePageRequiresAuthorization() 34 | { 35 | var client = this.server.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); 36 | var response = await client.GetAsync("Identity/Account/Manage"); 37 | 38 | Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Data/AYN.Data/Migrations/20210717203405_RenameCategoryPictureFieldToImageUrlAndRemoveLengthRestrictions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace AYN.Data.Migrations 4 | { 5 | public partial class RenameCategoryPictureFieldToImageUrlAndRemoveLengthRestrictions : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.DropColumn( 10 | name: "PictureExtension", 11 | table: "Categories"); 12 | 13 | migrationBuilder.AddColumn<string>( 14 | name: "ImageUrl", 15 | table: "Categories", 16 | type: "nvarchar(max)", 17 | nullable: false, 18 | defaultValue: string.Empty); 19 | } 20 | 21 | protected override void Down(MigrationBuilder migrationBuilder) 22 | { 23 | migrationBuilder.DropColumn( 24 | name: "ImageUrl", 25 | table: "Categories"); 26 | 27 | migrationBuilder.AddColumn<string>( 28 | name: "PictureExtension", 29 | table: "Categories", 30 | type: "nvarchar(6)", 31 | maxLength: 6, 32 | nullable: false, 33 | defaultValue: string.Empty); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Posts/GetUserPostsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | using AutoMapper; 5 | using AYN.Data.Models; 6 | using AYN.Data.Models.Enumerations; 7 | using AYN.Services.Mapping; 8 | 9 | namespace AYN.Web.ViewModels.Posts; 10 | 11 | public class GetUserPostsViewModel : IMapFrom<Post>, IHaveCustomMappings 12 | { 13 | public int Id { get; set; } 14 | 15 | public string Title { get; set; } 16 | 17 | public string Content { get; set; } 18 | 19 | public DateTime CreatedOn { get; set; } 20 | 21 | public DateTime ModifiedOn { get; set; } 22 | 23 | public int TotalReacts { get; set; } 24 | 25 | public ReactionType ReactionType { get; set; } 26 | 27 | public string ApplicationUserId { get; set; } 28 | 29 | public string ApplicationUserFirstName { get; set; } 30 | 31 | public string ApplicationUserLastName { get; set; } 32 | 33 | public string ApplicationUserAvatarImageUrl { get; set; } 34 | 35 | public void CreateMappings(IProfileExpression configuration) 36 | { 37 | configuration 38 | .CreateMap<Post, GetUserPostsViewModel>() 39 | .ForMember(m => m.TotalReacts, opt => opt.MapFrom(o => o.PostReacts.Count)) 40 | .ForMember(m => m.ReactionType, opt => opt.MapFrom(o => o.PostReacts.Select(a => a.ReactionType).FirstOrDefault())); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Components/GetMoreAdsFromUser/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Ads.ListMoreAdsByUserViewModel 2 | 3 | @if (this.Model.Ads.Any()) 4 | { 5 | <div class="card-deck"> 6 | <div class="card"> 7 | <div class="card-body"> 8 | <h5 class="card-title text-center">More from this user</h5> 9 | <hr /> 10 | @{ var counter = 0; } 11 | @foreach (var ad in this.Model.Ads) 12 | { 13 | var side = "right"; 14 | @if (counter % 2 == 0) 15 | { 16 | side = "left"; 17 | } 18 | 19 | <div class="float-@side"> 20 | <img class="card-img-top" src="@ad.TitleImageUrl" alt="Card image cap" style="width: 100px; height: 100px;"> 21 | <div class="float-center"> 22 | <a asp-controller="Ads" asp-action="Details" asp-route-id="@ad.Id" class="text-primary card-text text-center" data-toggle="tooltip" data-html="true" data-placement="top" title="@ad.Name">@ad.ShortName... @ad.Price.ToString("f0")$</a> 23 | </div> 24 | </div> 25 | 26 | counter++; 27 | } 28 | </div> 29 | </div> 30 | </div> 31 | } -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/AYN.Web.ViewModels.csproj: -------------------------------------------------------------------------------- 1 | <Project Sdk="Microsoft.NET.Sdk"> 2 | 3 | <PropertyGroup> 4 | <TargetFramework>net7.0</TargetFramework> 5 | <LangVersion>latest</LangVersion> 6 | </PropertyGroup> 7 | 8 | <PropertyGroup> 9 | <CodeAnalysisRuleSet>..\..\Rules.ruleset</CodeAnalysisRuleSet> 10 | </PropertyGroup> 11 | <ItemGroup> 12 | <AdditionalFiles Include="..\..\stylecop.json" /> 13 | </ItemGroup> 14 | 15 | <ItemGroup> 16 | <PackageReference Include="HtmlSanitizer" Version="8.0.723" /> 17 | <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312" PrivateAssets="all"> 18 | <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> 19 | </PackageReference> 20 | <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> 21 | </ItemGroup> 22 | 23 | <ItemGroup> 24 | <ProjectReference Include="..\..\Data\AYN.Data.Models\AYN.Data.Models.csproj" /> 25 | <ProjectReference Include="..\..\Services\AYN.Services.Mapping\AYN.Services.Mapping.csproj" /> 26 | 27 | </ItemGroup> 28 | 29 | <ItemGroup> 30 | <Folder Include="Administration\Ads\" /> 31 | <Folder Include="Administration\Chat\" /> 32 | <Folder Include="Feedback\" /> 33 | <Folder Include="Payments\" /> 34 | <Folder Include="SubCategories\" /> 35 | </ItemGroup> 36 | 37 | </Project> -------------------------------------------------------------------------------- /Services/AYN.Services.Data/AYN.Services.Data.csproj: -------------------------------------------------------------------------------- 1 | <Project Sdk="Microsoft.NET.Sdk"> 2 | 3 | <PropertyGroup> 4 | <TargetFramework>net7.0</TargetFramework> 5 | <LangVersion>latest</LangVersion> 6 | </PropertyGroup> 7 | 8 | <PropertyGroup> 9 | <CodeAnalysisRuleSet>..\..\Rules.ruleset</CodeAnalysisRuleSet> 10 | </PropertyGroup> 11 | <ItemGroup> 12 | <AdditionalFiles Include="..\..\stylecop.json" /> 13 | </ItemGroup> 14 | 15 | <ItemGroup> 16 | <PackageReference Include="CloudinaryDotNet" Version="1.15.2" /> 17 | <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312" PrivateAssets="all"> 18 | <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> 19 | </PackageReference> 20 | <PackageReference Include="SixLabors.ImageSharp" Version="2.1.7" /> 21 | <PackageReference Include="System.Drawing.Common" Version="6.0.0" /> 22 | <PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="6.13.5" /> 23 | </ItemGroup> 24 | 25 | <ItemGroup> 26 | <ProjectReference Include="..\..\Data\AYN.Data.Common\AYN.Data.Common.csproj" /> 27 | <ProjectReference Include="..\..\Data\AYN.Data.Models\AYN.Data.Models.csproj" /> 28 | <ProjectReference Include="..\..\Web\AYN.Web.ViewModels\AYN.Web.ViewModels.csproj" /> 29 | <ProjectReference Include="..\AYN.Services.Mapping\AYN.Services.Mapping.csproj" /> 30 | </ItemGroup> 31 | 32 | </Project> -------------------------------------------------------------------------------- /Data/AYN.Data/Seeding/Seeders/WordBlacklistSeeder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | 6 | using AngleSharp.Html.Parser; 7 | using AYN.Data.Models; 8 | using AYN.Data.Seeding.Interfaces; 9 | 10 | namespace AYN.Data.Seeding.Seeders; 11 | 12 | public class WordBlacklistSeeder : ISeeder 13 | { 14 | public async Task SeedAsync(ApplicationDbContext dbContext, IServiceProvider serviceProvider) 15 | { 16 | if (!dbContext.WordsBlacklist.Any()) 17 | { 18 | var wordsUrl = "https://www.cs.cmu.edu/~biglou/resources/bad-words.txt"; 19 | 20 | var parser = new HtmlParser(); 21 | var httpClient = new HttpClient(); 22 | 23 | var html = await httpClient.GetStringAsync(wordsUrl); 24 | 25 | var document = parser.ParseDocument(html); 26 | 27 | var words = document 28 | .QuerySelectorAll("body") 29 | .Select(e => e.InnerHtml.Split()) 30 | .ToList(); 31 | 32 | var wordsToAdd = 33 | (from word in words[0] 34 | where !string.IsNullOrEmpty(word) 35 | select new WordBlacklist { Content = word, }).ToList(); 36 | 37 | await dbContext.WordsBlacklist.AddRangeAsync(wordsToAdd); 38 | await dbContext.SaveChangesAsync(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Web/AYN.Web/wwwroot/scss/custom/mixins/_base.scss: -------------------------------------------------------------------------------- 1 | @mixin transition($time, $type){ 2 | -webkit-transition: all $time $type; 3 | -moz-transition: all $time $type; 4 | -o-transition: all $time $type; 5 | -ms-transition: all $time $type; 6 | transition: all $time $type; 7 | } 8 | 9 | @mixin box-shadow($shadow...) { 10 | -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 11 | box-shadow: $shadow; 12 | } 13 | 14 | // Opacity 15 | 16 | @mixin opacity($opacity) { 17 | opacity: $opacity; 18 | // IE8 filter 19 | $opacity-ie: ($opacity * 100); 20 | filter: #{alpha(opacity=$opacity-ie)}; 21 | } 22 | 23 | @mixin background-color($color) { 24 | background-color: $color !important; 25 | } 26 | 27 | @mixin table-color($color) { 28 | tbody, 29 | tr, 30 | th, 31 | td { 32 | background-color: rgba($color, 0.3); 33 | border-color: rgba($color, 0.3); 34 | color: darken($color, 40%); 35 | } 36 | } 37 | 38 | @mixin table-hover($color) { 39 | &:hover { 40 | th, td { 41 | background-color: rgba($color, 0.35); 42 | border-color: rgba($color, 0.35); 43 | } 44 | } 45 | } 46 | 47 | @mixin background-image($x_url){ 48 | background-image: url($x_url); 49 | background-position: center center; 50 | background-size: cover; 51 | position: relative; 52 | width: 100%; 53 | z-index: 1; 54 | } 55 | 56 | @mixin filter-color($color){ 57 | background-color: darken($color, 10%); 58 | } -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IUsersService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using AYN.Web.ViewModels.Administration.Users; 6 | using AYN.Web.ViewModels.Users; 7 | 8 | namespace AYN.Services.Data.Interfaces; 9 | 10 | public interface IUsersService 11 | { 12 | Task<IEnumerable<T>> GetAll<T>(); 13 | 14 | Task<T> GetProfileDetails<T>(string id); 15 | 16 | Task Follow(string followerId, string followeeId); 17 | 18 | Task Unfollow(string followerId, string followeeId); 19 | 20 | Task<IEnumerable<T>> GetFollowers<T>(string userId); 21 | 22 | Task<IEnumerable<T>> GetFollowings<T>(string userId); 23 | 24 | bool IsFollower(string followerId, string followeeId); 25 | 26 | bool IsUserExisting(string userId); 27 | 28 | Task<string> GenerateDefaultAvatar(string firstName, string lastName); 29 | 30 | Task<string> GenerateDefaultThumbnail(string firstName, string lastName); 31 | 32 | Task<T> GetByIdAsync<T>(string id); 33 | 34 | Task EditAsync(EditUserViewModel model, string wwwRootPath); 35 | 36 | Task<IEnumerable<T>> GetSuggestionPeople<T>(string userId, string openedUserId); 37 | 38 | Tuple<int, int, int> GetCounts(); 39 | 40 | Task Ban(BanUserInputModel input, string userId); 41 | 42 | Task Unban(string userId); 43 | 44 | string GetIdByUsername(string username); 45 | 46 | bool IsEmailTaken(string email); 47 | } 48 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Posts/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Posts.EditPostInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Edit post"; 5 | } 6 | 7 | <form method="post" class="col-md-6 offset-md-3 text-center" enctype="multipart/form-data"> 8 | <hr /> 9 | <div asp-validation-summary="All" class="text-danger"></div> 10 | <br /> 11 | <div> 12 | <span asp-validation-for="Title" class="text-danger"></span> 13 | 14 | <div class="input-group mb-3"> 15 | <div class="input-group-prepend"> 16 | <label asp-for="Title" class="input-group-text"> 17 | <i class="fas fa-file-signature"></i> 18 | </label> 19 | </div> 20 | 21 | <input asp-for="Title" placeholder="Title" class="form-control" /> 22 | </div> 23 | </div> 24 | 25 | <div> 26 | <span asp-validation-for="Content" class="text-danger"></span> 27 | 28 | <div class="input-group mb-3"> 29 | <div class="input-group-prepend"> 30 | <label asp-for="Title" class="input-group-text"> 31 | <i class="fas fa-file-signature"></i> 32 | </label> 33 | </div> 34 | 35 | <textarea asp-for="Content" rows="4" placeholder="Content" class="form-control"></textarea> 36 | </div> 37 | </div> 38 | 39 | <button type="submit" class="btn btn-primary btn-sm">Submit</button> 40 | <hr /> 41 | </form> -------------------------------------------------------------------------------- /Tests/AYN.Web.Tests/AYN.Web.Tests.csproj: -------------------------------------------------------------------------------- 1 | <Project Sdk="Microsoft.NET.Sdk.Web"> 2 | 3 | <PropertyGroup> 4 | <TargetFramework>net7.0</TargetFramework> 5 | <LangVersion>latest</LangVersion> 6 | </PropertyGroup> 7 | 8 | <PropertyGroup> 9 | <CodeAnalysisRuleSet>..\..\Rules.ruleset</CodeAnalysisRuleSet> 10 | </PropertyGroup> 11 | <ItemGroup> 12 | <AdditionalFiles Include="..\..\stylecop.json" /> 13 | </ItemGroup> 14 | 15 | <ItemGroup> 16 | <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.1" /> 17 | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> 18 | <PackageReference Include="Selenium.WebDriver" Version="4.0.0-alpha07" /> 19 | <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="90.0.4430.2400" /> 20 | <PackageReference Include="xunit" Version="2.4.1" /> 21 | <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> 22 | <PrivateAssets>all</PrivateAssets> 23 | <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> 24 | </PackageReference> 25 | <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312" PrivateAssets="all"> 26 | <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> 27 | </PackageReference> 28 | </ItemGroup> 29 | 30 | <ItemGroup> 31 | <ProjectReference Include="..\..\Web\AYN.Web\AYN.Web.csproj" /> 32 | </ItemGroup> 33 | 34 | </Project> 35 | -------------------------------------------------------------------------------- /Web/AYN.Web.ViewModels/Users/GetUserProfileBaseDetailsViewModel.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using AYN.Data.Models; 3 | using AYN.Services.Mapping; 4 | 5 | namespace AYN.Web.ViewModels.Users; 6 | 7 | public class GetUserProfileBaseDetailsViewModel : IMapFrom<ApplicationUser>, IHaveCustomMappings 8 | { 9 | public string Id { get; set; } 10 | 11 | public int PagingId { get; set; } 12 | 13 | public string FirstName { get; set; } 14 | 15 | public string LastName { get; set; } 16 | 17 | public string About { get; set; } 18 | 19 | public string AvatarImageUrl { get; set; } 20 | 21 | public string ThumbnailImageUrl { get; set; } 22 | 23 | public int FolloweesCount { get; set; } 24 | 25 | public int FollowingsCount { get; set; } 26 | 27 | public bool IsCurrentUserFollower { get; set; } 28 | 29 | public string FacebookUrl { get; set; } 30 | 31 | public string InstagramUrl { get; set; } 32 | 33 | public string TikTokUrl { get; set; } 34 | 35 | public string TwitterUrl { get; set; } 36 | 37 | public string WebsiteUrl { get; set; } 38 | 39 | public void CreateMappings(IProfileExpression configuration) 40 | { 41 | configuration 42 | .CreateMap<ApplicationUser, GetUserProfileBaseDetailsViewModel>() 43 | .ForMember(m => m.FolloweesCount, opt => opt.MapFrom(o => o.Followings.Count)) 44 | .ForMember(m => m.FollowingsCount, opt => opt.MapFrom(o => o.Followers.Count)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Controllers/ChatController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | 4 | using AYN.Services.Data.Interfaces; 5 | using AYN.Web.ViewModels.Administration.Chat; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AYN.Web.Areas.Administration.Controllers; 9 | 10 | public class ChatController : AdministrationController 11 | { 12 | private readonly IWordsBlacklistService wordsBlacklistService; 13 | 14 | public ChatController(IWordsBlacklistService wordsBlacklistService) 15 | => this.wordsBlacklistService = wordsBlacklistService; 16 | 17 | public async Task<IActionResult> BlacklistedWords(int id = 1) 18 | { 19 | var blacklistedWords = await this.wordsBlacklistService.AllAsync<BlacklistWordViewModel>(); 20 | var blacklistWordAsArray = blacklistedWords as BlacklistWordViewModel[] ?? blacklistedWords.ToArray(); 21 | 22 | var viewModel = new ListBlacklistWordsViewModel 23 | { 24 | BlacklistedWords = blacklistWordAsArray.Skip((id - 1) * 70).Take(70), 25 | Count = blacklistWordAsArray.Count(), 26 | ItemsPerPage = 70, 27 | PageNumber = id, 28 | }; 29 | 30 | return this.View(viewModel); 31 | } 32 | 33 | public async Task<IActionResult> DeleteBlacklistedWord(int id) 34 | { 35 | await this.wordsBlacklistService.DeleteAsync(id); 36 | return this.RedirectToAction(nameof(this.BlacklistedWords)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Data/AYN.Data/Repositories/EfDeletableEntityRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | using AYN.Data.Common.Models; 5 | using AYN.Data.Common.Repositories; 6 | 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace AYN.Data.Repositories; 10 | 11 | public class EfDeletableEntityRepository<TEntity> : EfRepository<TEntity>, IDeletableEntityRepository<TEntity> 12 | where TEntity : class, IDeletableEntity 13 | { 14 | public EfDeletableEntityRepository(ApplicationDbContext context) 15 | : base(context) 16 | { 17 | } 18 | 19 | public override IQueryable<TEntity> All() 20 | => base.All().Where(x => !x.IsDeleted); 21 | 22 | public override IQueryable<TEntity> AllAsNoTracking() 23 | => base.AllAsNoTracking().Where(x => !x.IsDeleted); 24 | 25 | public IQueryable<TEntity> AllWithDeleted() 26 | => base.All().IgnoreQueryFilters(); 27 | 28 | public IQueryable<TEntity> AllAsNoTrackingWithDeleted() 29 | => base.AllAsNoTracking().IgnoreQueryFilters(); 30 | 31 | public void HardDelete(TEntity entity) 32 | => base.Delete(entity); 33 | 34 | public void Undelete(TEntity entity) 35 | { 36 | entity.IsDeleted = false; 37 | entity.DeletedOn = null; 38 | 39 | this.Update(entity); 40 | } 41 | 42 | public override void Delete(TEntity entity) 43 | { 44 | entity.IsDeleted = true; 45 | entity.DeletedOn = DateTime.UtcNow; 46 | 47 | this.Update(entity); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Controllers/EmojisController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using AYN.Services.Data.Interfaces; 4 | using AYN.Web.ViewModels.Administration.Emojis; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AYN.Web.Areas.Administration.Controllers; 8 | 9 | public class EmojisController : AdministrationController 10 | { 11 | private readonly IEmojisService emojisService; 12 | 13 | public EmojisController(IEmojisService emojisService) 14 | => this.emojisService = emojisService; 15 | 16 | [HttpGet] 17 | public IActionResult Create() 18 | => this.View(); 19 | 20 | [HttpPost] 21 | public async Task<IActionResult> Create(CreateEmojiInputModel input) 22 | { 23 | if (this.emojisService.IsExisting(input.Emoji)) 24 | { 25 | this.ModelState.AddModelError(string.Empty, "This emoji is already existing."); 26 | return this.View(); 27 | } 28 | 29 | await this.emojisService.CreateAsync(input); 30 | return this.RedirectToAction(nameof(this.All)); 31 | } 32 | 33 | [HttpGet] 34 | public async Task<IActionResult> All() 35 | => this.View(new ListEmojiViewModel 36 | { 37 | Emojis = await this.emojisService.GetAll<EmojiViewModel>(), 38 | }); 39 | 40 | [HttpGet] 41 | public async Task<IActionResult> Delete(int id) 42 | { 43 | await this.emojisService.Delete(id); 44 | return this.RedirectToAction(nameof(this.All)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Web/AYN.Web/Areas/Administration/Views/Categories/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Administration.Categories.EditCategoryInputModel 2 | 3 | @{ 4 | this.ViewData["Title"] = "Edit Category"; 5 | } 6 | 7 | <div class="text-center"> 8 | <h1>@this.ViewData["Title"]</h1> 9 | </div> 10 | 11 | <form method="post" class="col-md-6 offset-md-3 text-center" enctype="multipart/form-data"> 12 | <hr /> 13 | <div asp-validation-summary="All" class="text-danger"></div> 14 | <img src="/img/CategoriesPictures/@Model.Id.@Model.PictureExtension" class="rounded-circle category-image" alt="@Model.Name"> 15 | <br /> 16 | <br /> 17 | <div> 18 | <span asp-validation-for="Name" class="text-danger"></span> 19 | 20 | <div class="input-group mb-3"> 21 | <div class="input-group-prepend"> 22 | <label asp-for="Name" class="input-group-text"> 23 | <i class="fas fa-file-signature"></i> 24 | </label> 25 | </div> 26 | 27 | <input asp-for="Name" placeholder="Name" class="form-control" /> 28 | </div> 29 | </div> 30 | 31 | <div class="form-group"> 32 | <label for="customFile">Change the category picture<br />(optional)</label> 33 | <input type="file" class="form-control-file" id="customFile" asp-for="Picture" /> 34 | <span asp-validation-for="Picture" class="text-danger"></span> 35 | </div> 36 | 37 | <button type="submit" class="btn btn-primary btn-sm">Submit</button> 38 | <hr /> 39 | </form> -------------------------------------------------------------------------------- /Services/AYN.Services.Data/Interfaces/IAdsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using AYN.Web.ViewModels.Ads; 6 | 7 | namespace AYN.Services.Data.Interfaces; 8 | 9 | public interface IAdsService 10 | { 11 | Task CreateAsync(CreateAdInputModel input, string userId); 12 | 13 | Task<IEnumerable<T>> GetRecent12AdsAsync<T>(); 14 | 15 | Task<IEnumerable<T>> GetRecent12PromotedAdsAsync<T>(); 16 | 17 | IEnumerable<T> GetAll<T>(string search = null, string town = null, string orderBy = null, int? categoryId = null, string letter = null); 18 | 19 | int GetCount(); 20 | 21 | Task<T> GetDetails<T>(string id); 22 | 23 | Task<IEnumerable<T>> GetUserAllAds<T>(string userId); 24 | 25 | Task<IEnumerable<T>> GetUserRecentAds<T>(string userId); 26 | 27 | Task<IEnumerable<T>> GetMoreFromUserAds<T>(string townName, int categoryId, int subCategoryId, string userId, string currentAdId); 28 | 29 | Task<IEnumerable<string>> GetAdsStartingLetters(); 30 | 31 | Tuple<int, int, int, int> GetCounts(); 32 | 33 | Task Archive(string adId); 34 | 35 | Task UnArchive(string adId); 36 | 37 | Task Delete(string adId); 38 | 39 | Task Promote(DateTime promoteUntil, string adId); 40 | 41 | Task UnPromote(string adId); 42 | 43 | bool IsAdExisting(string adId); 44 | 45 | Task<T> GetByIdAsync<T>(string adId); 46 | 47 | Task EditAsync(EditAdInputModel input); 48 | 49 | bool IsUserOwnsGivenAd(string userId, string adId); 50 | } 51 | -------------------------------------------------------------------------------- /Tests/AYN.Web.Tests/SeleniumTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | using OpenQA.Selenium; 5 | using OpenQA.Selenium.Chrome; 6 | 7 | using Xunit; 8 | 9 | namespace AYN.Web.Tests; 10 | 11 | public class SeleniumTests : IClassFixture<SeleniumServerFactory<Startup>>, IDisposable 12 | { 13 | private readonly SeleniumServerFactory<Startup> server; 14 | private readonly IWebDriver browser; 15 | 16 | public SeleniumTests(SeleniumServerFactory<Startup> server) 17 | { 18 | this.server = server; 19 | server.CreateClient(); 20 | 21 | var opts = new ChromeOptions(); 22 | 23 | opts.AddArguments("--headless"); 24 | opts.AcceptInsecureCertificates = true; 25 | 26 | this.browser = new ChromeDriver(opts); 27 | } 28 | 29 | [Fact(Skip = "Example test. Disabled for CI.")] 30 | public void FooterOfThePageContainsPrivacyLink() 31 | { 32 | this.browser 33 | .Navigate() 34 | .GoToUrl(this.server.RootUri); 35 | 36 | Assert.EndsWith( 37 | "/Home/Privacy", 38 | this.browser.FindElements(By.CssSelector("footer a")).First().GetAttribute("href")); 39 | } 40 | 41 | public void Dispose() 42 | { 43 | this.Dispose(true); 44 | GC.SuppressFinalize(this); 45 | } 46 | 47 | protected virtual void Dispose(bool disposing) 48 | { 49 | if (disposing) 50 | { 51 | this.server?.Dispose(); 52 | this.browser?.Dispose(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Web/AYN.Web/Views/Shared/Components/GetUserRecentAdViews/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model AYN.Web.ViewModels.Users.ListUserAdsViewModel 2 | 3 | 4 | <div class="card" > 5 | <div class="card-body"> 6 | <div id="carouselExampleIndicators1" class="carousel slide" data-ride="carousel"> 7 | <div class="carousel-inner"> 8 | @{ var counter = 1;} 9 | @foreach (var image in this.Model.Ads) 10 | { 11 | <div class="carousel-@(counter == 1 ? "item active" : "item")"> 12 | <a asp-controller="Ads" asp-action="Details" asp-route-id="@image.Id"><img class="d-block w-100" src="@image.ImageUrl"></a> 13 | <div class="text-center"> 14 | <h6 class="text-danger">@image.Name</h6><br /> 15 | </div> 16 | </div> 17 | counter++; 18 | } 19 | </div> 20 | <a class="carousel-control-prev" href="#carouselExampleIndicators1" role="button" data-slide="prev"> 21 | <span class="carousel-control-prev-icon" aria-hidden="true"></span> 22 | <span class="sr-only">Previous</span> 23 | </a> 24 | <a class="carousel-control-next" href="#carouselExampleIndicators1" role="button" data-slide="next"> 25 | <span class="carousel-control-next-icon" aria-hidden="true"></span> 26 | <span class="sr-only">Next</span> 27 | </a> 28 | </div> 29 | </div> 30 | </div> --------------------------------------------------------------------------------