From 04804b89a9be9868bb6fd74e2bab204ceb59ab08 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Wed, 16 Jul 2014 20:35:03 +0200 Subject: [PATCH] Initial import --- Banner.xcf | Bin 0 -> 120519 bytes ITContent/IITContent.cs | 21 + ITContent/ITContent.csproj | 49 + ITContent/Properties/AssemblyInfo.cs | 22 + NpgsqlBlogProvider/AssemblyInfo.cs | 27 + NpgsqlBlogProvider/BlogHelper.cs | 35 + NpgsqlBlogProvider/BlogManager.cs | 61 + NpgsqlBlogProvider/BlogProvider.cs | 32 + .../BlogProviderConfigurationElement.cs | 40 + .../BlogProvidersConfigurationCollection.cs | 26 + .../BlogProvidersConfigurationSection.cs | 26 + NpgsqlBlogProvider/DataModel/Blog.cs | 26 + NpgsqlBlogProvider/DataModel/BlogEntry.cs | 91 ++ .../DataModel/BlogEntryCollection.cs | 12 + NpgsqlBlogProvider/DataModel/Comment.cs | 76 ++ .../DataModel/FindBlogEntryFlags.cs | 16 + NpgsqlBlogProvider/NpgsqlBlogProvider.cs | 340 +++++ NpgsqlBlogProvider/NpgsqlBlogProvider.csproj | 70 + NpgsqlBlogProvider/Sql/BlogTable.sql | 21 + NpgsqlMRPProviders/AssemblyInfo.cs | 27 + NpgsqlMRPProviders/NpgsqlMRPProviders.csproj | 68 + .../NpgsqlMembershipProvider.cs | 1211 +++++++++++++++++ NpgsqlMRPProviders/NpgsqlProfileProvider.cs | 237 ++++ NpgsqlMRPProviders/NpgsqlRoleProvider.cs | 364 +++++ NpgsqlMRPProviders/Sql/ProfileData.sql | 28 + NpgsqlMRPProviders/Sql/RolesTable.sql | 18 + NpgsqlMRPProviders/Sql/StockSymbols.sql | 16 + NpgsqlMRPProviders/Sql/UserRoleTable.sql | 21 + NpgsqlMRPProviders/Sql/UsersTable.sql | 19 + SalesCatalog/AssemblyInfo.cs | 27 + SalesCatalog/CatalogHelper.cs | 45 + SalesCatalog/CatalogManager.cs | 19 + SalesCatalog/CatalogProvider.cs | 16 + .../CatalogProviderConfigurationElement.cs | 39 + ...CatalogProvidersConfigurationCollection.cs | 26 + .../CatalogProvidersConfigurationSection.cs | 26 + SalesCatalog/Model/Brand.cs | 37 + SalesCatalog/Model/Catalog.cs | 53 + SalesCatalog/Model/CheckBox.cs | 18 + SalesCatalog/Model/Currency.cs | 9 + SalesCatalog/Model/Euro.cs | 34 + SalesCatalog/Model/FilesInput.cs | 18 + SalesCatalog/Model/FormElement.cs | 10 + SalesCatalog/Model/FormInput.cs | 19 + SalesCatalog/Model/Label.cs | 18 + SalesCatalog/Model/Link.cs | 15 + SalesCatalog/Model/Note.cs | 13 + SalesCatalog/Model/Option.cs | 19 + SalesCatalog/Model/Period.cs | 15 + SalesCatalog/Model/PhysicalProduct.cs | 27 + SalesCatalog/Model/Price.cs | 36 + SalesCatalog/Model/Product.cs | 37 + SalesCatalog/Model/ProductCategory.cs | 23 + SalesCatalog/Model/ProductImage.cs | 23 + SalesCatalog/Model/RadioButton.cs | 17 + SalesCatalog/Model/SaleForm.cs | 20 + SalesCatalog/Model/Scalar.cs | 14 + SalesCatalog/Model/SelectInput.cs | 20 + SalesCatalog/Model/SelectItem.cs | 23 + SalesCatalog/Model/Service.cs | 28 + SalesCatalog/Model/StockStatus.cs | 11 + SalesCatalog/Model/Text.cs | 18 + SalesCatalog/Model/TextInput.cs | 46 + SalesCatalog/Model/Unit.cs | 13 + SalesCatalog/SalesCatalog.csproj | 102 ++ SalesCatalog/Tests/TestBrands.cs | 31 + SalesCatalog/Tests/TestCatalogInit.cs | 106 ++ SalesCatalog/XmlImplementation/XmlCatalog.cs | 15 + .../XmlImplementation/XmlCatalogProvider.cs | 55 + SalesCatalog/catalog.xsd | 151 ++ WebControls/Properties/AssemblyInfo.cs | 23 + WebControls/ResultPages.cs | 116 ++ WebControls/WebControls.csproj | 49 + WorkFlowProvider/NpgsqlContentProvider.cs | 148 ++ WorkFlowProvider/Properties/AssemblyInfo.cs | 22 + WorkFlowProvider/WFManager.cs | 18 + WorkFlowProvider/WorkFlowProvider.csproj | 49 + Yavsc.sln | 74 + mkReleaseSourceCode.sh | 1 + noavatar.xcf | Bin 0 -> 5885 bytes vscadm/Program.cs | 15 + vscadm/Properties/AssemblyInfo.cs | 22 + vscadm/vscadm.csproj | 42 + web/Admin/DataManager.cs | 81 ++ web/Admin/Export.cs | 14 + web/Admin/TaskOutput.cs | 12 + web/AssemblyInfo.cs | 27 + web/Basket/Basket.cs | 17 + web/CatExts/WebCatalogExtensions.cs | 80 ++ web/Catalog.xml | 56 + web/Controllers/AccountController.cs | 369 +++++ web/Controllers/BackOfficeController.cs | 66 + web/Controllers/BasketController.cs | 71 + web/Controllers/BlogsController.cs | 269 ++++ web/Controllers/Commande.cs | 21 + web/Controllers/FileSystemController.cs | 127 ++ web/Controllers/FrontOfficeApiController.cs | 85 ++ web/Controllers/FrontOfficeController.cs | 128 ++ web/Controllers/HomeController.cs | 101 ++ web/Controllers/T.cs | 22 + web/Controllers/WorkFlowController.cs | 51 + web/FileInfoCollection.cs | 15 + web/Global.asax | 1 + web/Global.asax.cs | 69 + web/Helpers/BBCodeHelper.cs | 349 +++++ web/Helpers/YavscHelpers.cs | 19 + web/Models/App.master | 61 + web/README | 45 + web/RegistrationMail.txt | 9 + web/Test/TestByteA.cs | 87 ++ web/Tests.cs | 19 + web/TextWriterOutput.log | 0 web/Thanks/ThanksConfigurationCollection.cs | 22 + web/Thanks/ThanksConfigurationElement.cs | 48 + web/Thanks/ThanksConfigurationSection.cs | 39 + web/Thanks/ThanksHelper.cs | 38 + web/Views/Account/AddRole.aspx | 19 + web/Views/Account/Admin.aspx | 34 + web/Views/Account/ChangePassword.aspx | 26 + web/Views/Account/ChangePasswordSuccess.aspx | 8 + web/Views/Account/Index.aspx | 8 + web/Views/Account/Login.aspx | 28 + web/Views/Account/Profile.aspx | 47 + web/Views/Account/Register.aspx | 45 + web/Views/Account/RegistrationPending.aspx | 17 + web/Views/Account/RemoveRoleQuery.aspx | 22 + web/Views/Account/RemoveUserQuery.aspx | 22 + web/Views/Account/RoleList.aspx | 23 + web/Views/Account/UserList.aspx | 22 + web/Views/Account/Validate.aspx | 8 + web/Views/BackOffice/BackupCreated.aspx | 13 + web/Views/BackOffice/Backups.aspx | 12 + web/Views/BackOffice/CreateBackup.aspx | 27 + web/Views/BackOffice/Index.aspx | 8 + web/Views/BackOffice/Restore.aspx | 43 + web/Views/BackOffice/Restored.aspx | 12 + web/Views/Blogs/Edit.aspx | 67 + web/Views/Blogs/Error.aspx | 14 + web/Views/Blogs/Index.aspx | 34 + web/Views/Blogs/Post.aspx | 67 + web/Views/Blogs/TitleNotFound.aspx | 17 + web/Views/Blogs/UserPost.aspx | 47 + web/Views/Blogs/UserPosts.aspx | 42 + web/Views/FileSystem/Create.aspx | 20 + web/Views/FileSystem/Delete.aspx | 7 + web/Views/FileSystem/Details.aspx | 15 + web/Views/FileSystem/Edit.aspx | 9 + web/Views/FileSystem/Index.aspx | 16 + web/Views/FrontOffice/Brand.aspx | 32 + web/Views/FrontOffice/Catalog.aspx | 32 + web/Views/FrontOffice/Command.aspx | 7 + web/Views/FrontOffice/Product.aspx | 30 + web/Views/FrontOffice/ProductCategory.aspx | 23 + web/Views/FrontOffice/ReferenceNotFound.aspx | 7 + web/Views/FrontOffice/Service.aspx | 31 + web/Views/Home/AOEMail.aspx | 7 + web/Views/Home/Index.aspx | 8 + web/Views/Home/NCView.aspx | 3 + web/Views/Home/NView.aspx | 12 + web/Views/Home/Thanks.ascx | 17 + web/Views/RegisterPage.cs | 28 + web/Views/Web.config | 41 + web/Views/WorkFlow/Index.aspx | 11 + web/Views/WorkFlow/NewProject.aspx | 22 + web/Web.config | 215 +++ web/Web.csproj | 260 ++++ web/WebDeploy.targets | 10 + .../CustomErrorPages/CustomErrorPages.sln | 9 + .../CustomErrorPages.userprefs | 10 + .../CustomErrors1/AssemblyInfo.cs | 62 + .../CustomErrors1/CustomErrors1.csproj | 145 ++ .../CustomErrors1/Default.aspx | 11 + .../CustomErrors1/Default.aspx.cs | 41 + .../CustomErrors1/Default.aspx.resx | 109 ++ .../CustomErrors1/Global.asax | 1 + .../CustomErrors1/Global.asax.cs | 76 ++ .../CustomErrors1/Global.asax.resx | 42 + .../CustomErrors1/PageBase.cs | 32 + .../CustomErrorPages/CustomErrors1/Web.config | 101 ++ .../CustomErrors2/AssemblyInfo.cs | 62 + .../CustomErrors2/CustomErrors2.csproj | 140 ++ .../CustomErrors2/Default.aspx | 12 + .../CustomErrors2/Default.aspx.cs | 39 + .../CustomErrors2/Default.aspx.resx | 42 + .../CustomErrors2/Global.asax | 1 + .../CustomErrors2/Global.asax.cs | 91 ++ .../CustomErrors2/Global.asax.resx | 42 + .../CustomErrorPages/CustomErrors2/Web.config | 101 ++ .../CustomErrors3/AssemblyInfo.cs | 62 + .../CustomErrors3/CustomErrors3.csproj | 172 +++ .../CustomErrors3/Default.aspx | 17 + .../CustomErrors3/Default.aspx.cs | 39 + .../CustomErrors3/Default.aspx.resx | 42 + .../CustomErrors3/Global.asax | 1 + .../CustomErrors3/Global.asax.cs | 76 ++ .../CustomErrors3/Global.asax.resx | 42 + .../CustomErrorPages/CustomErrors3/Web.config | 101 ++ .../CustomErrors3/errors/GeneralError.aspx | 14 + .../CustomErrors3/errors/GeneralError.aspx.cs | 32 + .../errors/GeneralError.aspx.resx | 42 + .../CustomErrors3/errors/PageNotFound.aspx | 14 + .../CustomErrors3/errors/PageNotFound.aspx.cs | 32 + .../errors/PageNotFound.aspx.resx | 42 + .../CustomErrors4/AssemblyInfo.cs | 62 + .../CustomErrors4/CustomErrors4.csproj | 177 +++ .../CustomErrors4/Default.aspx | 11 + .../CustomErrors4/Default.aspx.cs | 40 + .../CustomErrors4/Default.aspx.resx | 42 + .../CustomErrors4/ErrorModule.cs | 35 + .../CustomErrors4/Global.asax | 1 + .../CustomErrors4/Global.asax.cs | 76 ++ .../CustomErrors4/Global.asax.resx | 42 + .../CustomErrorPages/CustomErrors4/Web.config | 105 ++ .../CustomErrors4/errors/GeneralError.aspx | 14 + .../CustomErrors4/errors/GeneralError.aspx.cs | 32 + .../errors/GeneralError.aspx.resx | 42 + .../CustomErrors4/errors/PageNotFound.aspx | 14 + .../CustomErrors4/errors/PageNotFound.aspx.cs | 32 + .../errors/PageNotFound.aspx.resx | 42 + web/errors/GeneralError.aspx | 14 + web/errors/PageNotFound.aspx | 14 + web/favicon.ico | Bin 0 -> 2238 bytes web/favicon.png | Bin 0 -> 3295 bytes web/genpot.sh | 9 + web/images/Banner.png | Bin 0 -> 93007 bytes web/images/Mono-powered.png | Bin 0 -> 1676 bytes web/images/apache_pb.gif | Bin 0 -> 2339 bytes web/images/apache_pbw.gif | Bin 0 -> 1640 bytes web/images/apache_pbw.png | Bin 0 -> 4181 bytes web/images/apache_pby.gif | Bin 0 -> 2359 bytes web/images/debian-logo.png | Bin 0 -> 3366 bytes web/images/debian-pb.gif | Bin 0 -> 2596 bytes web/images/debian-powered.png | Bin 0 -> 1818 bytes web/images/logoDev.png | Bin 0 -> 3295 bytes web/images/logoDev.xcf | Bin 0 -> 149953 bytes web/images/noavatar.png | Bin 0 -> 5491 bytes web/images/pgsql.jpeg | Bin 0 -> 4903 bytes web/images/pgsql.png | Bin 0 -> 2632 bytes web/images/pgsql.xcf | Bin 0 -> 10639 bytes web/instdbws.sql | 68 + web/lib/CodeKicker.BBCode.XML | 53 + web/lib/CodeKicker.BBCode.dll | Bin 0 -> 38400 bytes web/lib/CodeKicker.BBCode.pdb | Bin 0 -> 93696 bytes web/lib/de-DE/CodeKicker.BBCode.resources.dll | Bin 0 -> 5632 bytes web/lib/it-IT/CodeKicker.BBCode.resources.dll | Bin 0 -> 5632 bytes web/messages.po | 26 + web/sourcefiles | 36 + web/style.css | 149 ++ web/table.tdeps.sql | 6 + .../maeweb.csproj-Debug-2013-11-28.xml | 112 ++ .../maeweb.csproj-Debug-2013-12-12.xml | 141 ++ .../maeweb.csproj-Debug-2013-12-16.xml | 19 + web/test-results/maeweb.csproj.test-cache | Bin 0 -> 1312 bytes web/uninstdb.sql | 6 + web/uninstdbws.sql | 5 + yavscModel/Admin/DataAccess.cs | 84 ++ yavscModel/Admin/RestoreQuery.cs | 17 + yavscModel/Blogs/BlogEditCommentModel.cs | 26 + yavscModel/Blogs/BlogEditEntryModel.cs | 29 + yavscModel/FileSystem/FileInfoCollection.cs | 12 + yavscModel/Properties/AssemblyInfo.cs | 22 + .../RolesAndMemebers/ChangePasswordModel.cs | 22 + yavscModel/RolesAndMemebers/LoginModel.cs | 22 + yavscModel/RolesAndMemebers/NewAdminModel.cs | 13 + yavscModel/RolesAndMemebers/NewRoleModel.cs | 15 + yavscModel/RolesAndMemebers/Profile.cs | 63 + .../RolesAndMemebers/RegisterViewModel.cs | 25 + yavscModel/WorkFlow/Estimate.cs | 22 + yavscModel/WorkFlow/IContent.cs | 13 + yavscModel/WorkFlow/IContentProvider.cs | 12 + yavscModel/WorkFlow/IWFCommand.cs | 10 + yavscModel/WorkFlow/IWFModule.cs | 13 + yavscModel/WorkFlow/NewProjectModel.cs | 23 + yavscModel/WorkFlow/WFOrder.cs | 39 + yavscModel/WorkFlow/Writting.cs | 13 + yavscModel/yavscModel.csproj | 89 ++ yavscclient/MyClass.cs | 78 ++ yavscclient/Properties/AssemblyInfo.cs | 22 + yavscclient/YavscClient.csproj | 55 + 279 files changed, 12945 insertions(+) create mode 100644 Banner.xcf create mode 100644 ITContent/IITContent.cs create mode 100644 ITContent/ITContent.csproj create mode 100644 ITContent/Properties/AssemblyInfo.cs create mode 100644 NpgsqlBlogProvider/AssemblyInfo.cs create mode 100644 NpgsqlBlogProvider/BlogHelper.cs create mode 100644 NpgsqlBlogProvider/BlogManager.cs create mode 100644 NpgsqlBlogProvider/BlogProvider.cs create mode 100644 NpgsqlBlogProvider/Configuration/BlogProviderConfigurationElement.cs create mode 100644 NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationCollection.cs create mode 100644 NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationSection.cs create mode 100644 NpgsqlBlogProvider/DataModel/Blog.cs create mode 100644 NpgsqlBlogProvider/DataModel/BlogEntry.cs create mode 100644 NpgsqlBlogProvider/DataModel/BlogEntryCollection.cs create mode 100644 NpgsqlBlogProvider/DataModel/Comment.cs create mode 100644 NpgsqlBlogProvider/DataModel/FindBlogEntryFlags.cs create mode 100644 NpgsqlBlogProvider/NpgsqlBlogProvider.cs create mode 100644 NpgsqlBlogProvider/NpgsqlBlogProvider.csproj create mode 100644 NpgsqlBlogProvider/Sql/BlogTable.sql create mode 100644 NpgsqlMRPProviders/AssemblyInfo.cs create mode 100644 NpgsqlMRPProviders/NpgsqlMRPProviders.csproj create mode 100644 NpgsqlMRPProviders/NpgsqlMembershipProvider.cs create mode 100644 NpgsqlMRPProviders/NpgsqlProfileProvider.cs create mode 100644 NpgsqlMRPProviders/NpgsqlRoleProvider.cs create mode 100644 NpgsqlMRPProviders/Sql/ProfileData.sql create mode 100644 NpgsqlMRPProviders/Sql/RolesTable.sql create mode 100644 NpgsqlMRPProviders/Sql/StockSymbols.sql create mode 100644 NpgsqlMRPProviders/Sql/UserRoleTable.sql create mode 100644 NpgsqlMRPProviders/Sql/UsersTable.sql create mode 100644 SalesCatalog/AssemblyInfo.cs create mode 100644 SalesCatalog/CatalogHelper.cs create mode 100644 SalesCatalog/CatalogManager.cs create mode 100644 SalesCatalog/CatalogProvider.cs create mode 100644 SalesCatalog/Configuration/CatalogProviderConfigurationElement.cs create mode 100644 SalesCatalog/Configuration/CatalogProvidersConfigurationCollection.cs create mode 100644 SalesCatalog/Configuration/CatalogProvidersConfigurationSection.cs create mode 100644 SalesCatalog/Model/Brand.cs create mode 100644 SalesCatalog/Model/Catalog.cs create mode 100644 SalesCatalog/Model/CheckBox.cs create mode 100644 SalesCatalog/Model/Currency.cs create mode 100644 SalesCatalog/Model/Euro.cs create mode 100644 SalesCatalog/Model/FilesInput.cs create mode 100644 SalesCatalog/Model/FormElement.cs create mode 100644 SalesCatalog/Model/FormInput.cs create mode 100644 SalesCatalog/Model/Label.cs create mode 100644 SalesCatalog/Model/Link.cs create mode 100644 SalesCatalog/Model/Note.cs create mode 100644 SalesCatalog/Model/Option.cs create mode 100644 SalesCatalog/Model/Period.cs create mode 100644 SalesCatalog/Model/PhysicalProduct.cs create mode 100644 SalesCatalog/Model/Price.cs create mode 100644 SalesCatalog/Model/Product.cs create mode 100644 SalesCatalog/Model/ProductCategory.cs create mode 100644 SalesCatalog/Model/ProductImage.cs create mode 100644 SalesCatalog/Model/RadioButton.cs create mode 100644 SalesCatalog/Model/SaleForm.cs create mode 100644 SalesCatalog/Model/Scalar.cs create mode 100644 SalesCatalog/Model/SelectInput.cs create mode 100644 SalesCatalog/Model/SelectItem.cs create mode 100644 SalesCatalog/Model/Service.cs create mode 100644 SalesCatalog/Model/StockStatus.cs create mode 100644 SalesCatalog/Model/Text.cs create mode 100644 SalesCatalog/Model/TextInput.cs create mode 100644 SalesCatalog/Model/Unit.cs create mode 100644 SalesCatalog/SalesCatalog.csproj create mode 100644 SalesCatalog/Tests/TestBrands.cs create mode 100644 SalesCatalog/Tests/TestCatalogInit.cs create mode 100644 SalesCatalog/XmlImplementation/XmlCatalog.cs create mode 100644 SalesCatalog/XmlImplementation/XmlCatalogProvider.cs create mode 100644 SalesCatalog/catalog.xsd create mode 100644 WebControls/Properties/AssemblyInfo.cs create mode 100644 WebControls/ResultPages.cs create mode 100644 WebControls/WebControls.csproj create mode 100644 WorkFlowProvider/NpgsqlContentProvider.cs create mode 100644 WorkFlowProvider/Properties/AssemblyInfo.cs create mode 100644 WorkFlowProvider/WFManager.cs create mode 100644 WorkFlowProvider/WorkFlowProvider.csproj create mode 100644 Yavsc.sln create mode 100644 mkReleaseSourceCode.sh create mode 100644 noavatar.xcf create mode 100644 vscadm/Program.cs create mode 100644 vscadm/Properties/AssemblyInfo.cs create mode 100644 vscadm/vscadm.csproj create mode 100644 web/Admin/DataManager.cs create mode 100644 web/Admin/Export.cs create mode 100644 web/Admin/TaskOutput.cs create mode 100644 web/AssemblyInfo.cs create mode 100644 web/Basket/Basket.cs create mode 100644 web/CatExts/WebCatalogExtensions.cs create mode 100644 web/Catalog.xml create mode 100644 web/Controllers/AccountController.cs create mode 100644 web/Controllers/BackOfficeController.cs create mode 100644 web/Controllers/BasketController.cs create mode 100644 web/Controllers/BlogsController.cs create mode 100644 web/Controllers/Commande.cs create mode 100644 web/Controllers/FileSystemController.cs create mode 100644 web/Controllers/FrontOfficeApiController.cs create mode 100644 web/Controllers/FrontOfficeController.cs create mode 100644 web/Controllers/HomeController.cs create mode 100644 web/Controllers/T.cs create mode 100644 web/Controllers/WorkFlowController.cs create mode 100644 web/FileInfoCollection.cs create mode 100644 web/Global.asax create mode 100644 web/Global.asax.cs create mode 100644 web/Helpers/BBCodeHelper.cs create mode 100644 web/Helpers/YavscHelpers.cs create mode 100644 web/Models/App.master create mode 100644 web/README create mode 100644 web/RegistrationMail.txt create mode 100644 web/Test/TestByteA.cs create mode 100644 web/Tests.cs create mode 100644 web/TextWriterOutput.log create mode 100644 web/Thanks/ThanksConfigurationCollection.cs create mode 100644 web/Thanks/ThanksConfigurationElement.cs create mode 100644 web/Thanks/ThanksConfigurationSection.cs create mode 100644 web/Thanks/ThanksHelper.cs create mode 100644 web/Views/Account/AddRole.aspx create mode 100644 web/Views/Account/Admin.aspx create mode 100644 web/Views/Account/ChangePassword.aspx create mode 100644 web/Views/Account/ChangePasswordSuccess.aspx create mode 100644 web/Views/Account/Index.aspx create mode 100644 web/Views/Account/Login.aspx create mode 100644 web/Views/Account/Profile.aspx create mode 100644 web/Views/Account/Register.aspx create mode 100644 web/Views/Account/RegistrationPending.aspx create mode 100644 web/Views/Account/RemoveRoleQuery.aspx create mode 100644 web/Views/Account/RemoveUserQuery.aspx create mode 100644 web/Views/Account/RoleList.aspx create mode 100644 web/Views/Account/UserList.aspx create mode 100644 web/Views/Account/Validate.aspx create mode 100644 web/Views/BackOffice/BackupCreated.aspx create mode 100644 web/Views/BackOffice/Backups.aspx create mode 100644 web/Views/BackOffice/CreateBackup.aspx create mode 100644 web/Views/BackOffice/Index.aspx create mode 100644 web/Views/BackOffice/Restore.aspx create mode 100644 web/Views/BackOffice/Restored.aspx create mode 100644 web/Views/Blogs/Edit.aspx create mode 100644 web/Views/Blogs/Error.aspx create mode 100644 web/Views/Blogs/Index.aspx create mode 100644 web/Views/Blogs/Post.aspx create mode 100644 web/Views/Blogs/TitleNotFound.aspx create mode 100644 web/Views/Blogs/UserPost.aspx create mode 100644 web/Views/Blogs/UserPosts.aspx create mode 100644 web/Views/FileSystem/Create.aspx create mode 100644 web/Views/FileSystem/Delete.aspx create mode 100644 web/Views/FileSystem/Details.aspx create mode 100644 web/Views/FileSystem/Edit.aspx create mode 100644 web/Views/FileSystem/Index.aspx create mode 100644 web/Views/FrontOffice/Brand.aspx create mode 100644 web/Views/FrontOffice/Catalog.aspx create mode 100644 web/Views/FrontOffice/Command.aspx create mode 100644 web/Views/FrontOffice/Product.aspx create mode 100644 web/Views/FrontOffice/ProductCategory.aspx create mode 100644 web/Views/FrontOffice/ReferenceNotFound.aspx create mode 100644 web/Views/FrontOffice/Service.aspx create mode 100644 web/Views/Home/AOEMail.aspx create mode 100644 web/Views/Home/Index.aspx create mode 100644 web/Views/Home/NCView.aspx create mode 100644 web/Views/Home/NView.aspx create mode 100644 web/Views/Home/Thanks.ascx create mode 100644 web/Views/RegisterPage.cs create mode 100644 web/Views/Web.config create mode 100644 web/Views/WorkFlow/Index.aspx create mode 100644 web/Views/WorkFlow/NewProject.aspx create mode 100644 web/Web.config create mode 100644 web/Web.csproj create mode 100644 web/WebDeploy.targets create mode 100644 web/errors/CustomErrorPages/CustomErrorPages.sln create mode 100644 web/errors/CustomErrorPages/CustomErrorPages.userprefs create mode 100644 web/errors/CustomErrorPages/CustomErrors1/AssemblyInfo.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors1/CustomErrors1.csproj create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Default.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Default.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Default.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Global.asax create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Global.asax.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Global.asax.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors1/PageBase.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors1/Web.config create mode 100644 web/errors/CustomErrorPages/CustomErrors2/AssemblyInfo.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors2/CustomErrors2.csproj create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Default.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Default.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Default.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Global.asax create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Global.asax.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Global.asax.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors2/Web.config create mode 100644 web/errors/CustomErrorPages/CustomErrors3/AssemblyInfo.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors3/CustomErrors3.csproj create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Default.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Default.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Default.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Global.asax create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Global.asax.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Global.asax.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors3/Web.config create mode 100644 web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/AssemblyInfo.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors4/CustomErrors4.csproj create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Default.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Default.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Default.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/ErrorModule.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Global.asax create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Global.asax.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Global.asax.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/Web.config create mode 100644 web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.resx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx create mode 100644 web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.cs create mode 100644 web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.resx create mode 100644 web/errors/GeneralError.aspx create mode 100644 web/errors/PageNotFound.aspx create mode 100644 web/favicon.ico create mode 100644 web/favicon.png create mode 100644 web/genpot.sh create mode 100644 web/images/Banner.png create mode 100644 web/images/Mono-powered.png create mode 100644 web/images/apache_pb.gif create mode 100644 web/images/apache_pbw.gif create mode 100644 web/images/apache_pbw.png create mode 100644 web/images/apache_pby.gif create mode 100644 web/images/debian-logo.png create mode 100644 web/images/debian-pb.gif create mode 100644 web/images/debian-powered.png create mode 100644 web/images/logoDev.png create mode 100644 web/images/logoDev.xcf create mode 100644 web/images/noavatar.png create mode 100644 web/images/pgsql.jpeg create mode 100644 web/images/pgsql.png create mode 100644 web/images/pgsql.xcf create mode 100644 web/instdbws.sql create mode 100644 web/lib/CodeKicker.BBCode.XML create mode 100644 web/lib/CodeKicker.BBCode.dll create mode 100644 web/lib/CodeKicker.BBCode.pdb create mode 100644 web/lib/de-DE/CodeKicker.BBCode.resources.dll create mode 100644 web/lib/it-IT/CodeKicker.BBCode.resources.dll create mode 100644 web/messages.po create mode 100644 web/sourcefiles create mode 100644 web/style.css create mode 100644 web/table.tdeps.sql create mode 100644 web/test-results/maeweb.csproj-Debug-2013-11-28.xml create mode 100644 web/test-results/maeweb.csproj-Debug-2013-12-12.xml create mode 100644 web/test-results/maeweb.csproj-Debug-2013-12-16.xml create mode 100644 web/test-results/maeweb.csproj.test-cache create mode 100644 web/uninstdb.sql create mode 100644 web/uninstdbws.sql create mode 100644 yavscModel/Admin/DataAccess.cs create mode 100644 yavscModel/Admin/RestoreQuery.cs create mode 100644 yavscModel/Blogs/BlogEditCommentModel.cs create mode 100644 yavscModel/Blogs/BlogEditEntryModel.cs create mode 100644 yavscModel/FileSystem/FileInfoCollection.cs create mode 100644 yavscModel/Properties/AssemblyInfo.cs create mode 100644 yavscModel/RolesAndMemebers/ChangePasswordModel.cs create mode 100644 yavscModel/RolesAndMemebers/LoginModel.cs create mode 100644 yavscModel/RolesAndMemebers/NewAdminModel.cs create mode 100644 yavscModel/RolesAndMemebers/NewRoleModel.cs create mode 100644 yavscModel/RolesAndMemebers/Profile.cs create mode 100644 yavscModel/RolesAndMemebers/RegisterViewModel.cs create mode 100644 yavscModel/WorkFlow/Estimate.cs create mode 100644 yavscModel/WorkFlow/IContent.cs create mode 100644 yavscModel/WorkFlow/IContentProvider.cs create mode 100644 yavscModel/WorkFlow/IWFCommand.cs create mode 100644 yavscModel/WorkFlow/IWFModule.cs create mode 100644 yavscModel/WorkFlow/NewProjectModel.cs create mode 100644 yavscModel/WorkFlow/WFOrder.cs create mode 100644 yavscModel/WorkFlow/Writting.cs create mode 100644 yavscModel/yavscModel.csproj create mode 100644 yavscclient/MyClass.cs create mode 100644 yavscclient/Properties/AssemblyInfo.cs create mode 100644 yavscclient/YavscClient.csproj diff --git a/Banner.xcf b/Banner.xcf new file mode 100644 index 0000000000000000000000000000000000000000..10ccdb14c857b8683a2bc1d00466f4929b045eec GIT binary patch literal 120519 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 literal 0 HcmV?d00001 diff --git a/ITContent/IITContent.cs b/ITContent/IITContent.cs new file mode 100644 index 00000000..eeaab5d2 --- /dev/null +++ b/ITContent/IITContent.cs @@ -0,0 +1,21 @@ +using System; +using WorkFlowProvider; +using yavscModel.WorkFlow; + +namespace ITContent +{ + public interface IITContent: IContentProvider + { + int NewProject(string name, string desc, string ownedId); + void AddDevRessource (int prjId, string userName); + int NewTask(int projectId, string name, string desc); + void SetProjectName(int projectId, string name); + void SetProjectDesc(int projectId, string desc); + void SetTaskName(int taskId, string name); + void SetStartDate(int taskId, DateTime d); + void SetEndDate(int taskId, DateTime d); + void SetTaskDesc(int taskId, string desc); + void NewRelease(int projectId, string Version); + } +} + diff --git a/ITContent/ITContent.csproj b/ITContent/ITContent.csproj new file mode 100644 index 00000000..77e6106c --- /dev/null +++ b/ITContent/ITContent.csproj @@ -0,0 +1,49 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {88D83FC9-4158-4435-98A6-1F8F7F448B8F} + Library + ITContent + ITContent + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + {821FF72D-9F4B-4A2C-B95C-7B965291F119} + WorkFlowProvider + + + {68F5B80A-616E-4C3C-91A0-828AA40000BD} + yavscModel + + + \ No newline at end of file diff --git a/ITContent/Properties/AssemblyInfo.cs b/ITContent/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..ccc7943b --- /dev/null +++ b/ITContent/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("ITContent")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("Paul Schneider")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/NpgsqlBlogProvider/AssemblyInfo.cs b/NpgsqlBlogProvider/AssemblyInfo.cs new file mode 100644 index 00000000..7cc5217d --- /dev/null +++ b/NpgsqlBlogProvider/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("NpgsqlBlogProvider")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("paul")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/NpgsqlBlogProvider/BlogHelper.cs b/NpgsqlBlogProvider/BlogHelper.cs new file mode 100644 index 00000000..b08e339e --- /dev/null +++ b/NpgsqlBlogProvider/BlogHelper.cs @@ -0,0 +1,35 @@ +using System; +using System.Configuration; +using System.Reflection; +using System.Collections.Specialized; +using Npgsql.Web.Blog.Configuration; + +namespace Npgsql.Web.Blog +{ + public static class BlogHelper + { + public static BlogProvider GetProvider () + { + BlogProvidersConfigurationSection config = ConfigurationManager.GetSection ("system.web/blog") as BlogProvidersConfigurationSection; + if (config == null) + throw new ConfigurationErrorsException("The configuration bloc for the blog provider was not found"); + BlogProviderConfigurationElement celt = + config.Providers.GetElement (config.DefaultProvider); + if (config == null) + throw new ConfigurationErrorsException("The default blog provider was not found"); + ConstructorInfo ci = Type.GetType (celt.Type).GetConstructor (Type.EmptyTypes); + BlogProvider bp = ci.Invoke (Type.EmptyTypes) as BlogProvider; + NameValueCollection c = new NameValueCollection (); + c.Add ("name", celt.Name); + c.Add ("type", celt.Type); + c.Add ("connectionStringName", celt.ConnectionStringName); + c.Add ("description", celt.Description); + c.Add ("applicationName", celt.ApplicationName); + bp.Initialize (celt.Name, c); + return bp; + } + + + } + +} diff --git a/NpgsqlBlogProvider/BlogManager.cs b/NpgsqlBlogProvider/BlogManager.cs new file mode 100644 index 00000000..594f7a40 --- /dev/null +++ b/NpgsqlBlogProvider/BlogManager.cs @@ -0,0 +1,61 @@ +using System; +using Npgsql.Web.Blog.DataModel; + +namespace Npgsql.Web.Blog +{ + public static class BlogManager + { + public static long RemoveComment(long cmtid) + { + return Provider.RemoveComment (cmtid); + } + + public static void Comment (string from, long postid, string content, bool visible) + { + provider.Comment (from, postid, content); + } + + static BlogProvider provider; + + public static BlogProvider Provider { + get { + if (provider == null) + provider = BlogHelper.GetProvider(); + return provider; + } + } + public static BlogEntry GetPost (string username, string title) + { + return Provider.GetPost (username, title ); + } + public static BlogEntry GetPost(long postid) + { + return Provider.GetPost (postid); + } + public static void Post(string username, string title, string content, bool visible) + { + Provider.Post(username, title, content, visible ); + } + public static void UpdatePost(long postid, string content, bool visible) + { + Provider.UpdatePost(postid, content, visible); + } + public static BlogEntryCollection FindPost (string pattern, FindBlogEntryFlags searchflags, int pageIndex, int pageSize, out int totalRecords) + { + return Provider.FindPost (pattern, searchflags, pageIndex, pageSize, out totalRecords); + } + public static void RemovePost (string username, string title) + { + Provider.RemovePost (username, title); + } + public static BlogEntryCollection LastPosts (int pageIndex, int pageSize, out int totalRecords) + { + return Provider.LastPosts (pageIndex, pageSize, out totalRecords); + } + public static Comment[] GetComments(long postid, bool getHidden=true) + { + return Provider.GetComments (postid,getHidden); + } + } +} + diff --git a/NpgsqlBlogProvider/BlogProvider.cs b/NpgsqlBlogProvider/BlogProvider.cs new file mode 100644 index 00000000..fc579116 --- /dev/null +++ b/NpgsqlBlogProvider/BlogProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Configuration; +using System.Configuration.Provider; +using System.Collections.Generic; +using Npgsql.Web.Blog.DataModel; + +namespace Npgsql.Web.Blog +{ + public abstract class BlogProvider: ProviderBase + { + public abstract BlogEntry GetPost (long postid); + public abstract BlogEntry GetPost (string username, string title); + public abstract long GetPostId (string username, string title); + + public abstract long Post (string username, string title, string content, bool visible); + public abstract void UpdatePost (long postid, string content, bool visible); + public abstract BlogEntryCollection FindPost (string pattern, FindBlogEntryFlags searchflags, + int pageIndex, int pageSize, out int totalRecords); + public abstract void RemovePost (string username, string title); + public abstract void RemovePost (long postid); + public abstract long RemoveComment (long cmtid); + public abstract BlogEntryCollection LastPosts(int pageIndex, int pageSize, out int totalRecords); + public abstract string BlogTitle (string username); + public abstract long Comment (string from, long postid, string content); + public abstract Comment[] GetComments (long postid, bool getHidden) ; + public abstract bool AutoValidateComment { get; set; } + public abstract void ValidateComment (long cmtid); + public abstract void UpdateComment (long cmtid, string content, bool visible); + } + +} + diff --git a/NpgsqlBlogProvider/Configuration/BlogProviderConfigurationElement.cs b/NpgsqlBlogProvider/Configuration/BlogProviderConfigurationElement.cs new file mode 100644 index 00000000..6dd50742 --- /dev/null +++ b/NpgsqlBlogProvider/Configuration/BlogProviderConfigurationElement.cs @@ -0,0 +1,40 @@ +using System; +using System.Configuration; +using System.ComponentModel; + +namespace Npgsql.Web.Blog.Configuration +{ + + public class BlogProviderConfigurationElement : ConfigurationElement + { + [ConfigurationProperty("name", IsRequired = true, IsKey=true)] + public string Name { + get { return (string)this ["name"]; } + set { this ["name"] = value; } + } + + [ConfigurationProperty("type", IsRequired = true, IsKey=false)] + public string Type { + get { return (string)this ["type"]; } + set { this ["type"] = value; } + } + + [ConfigurationProperty("connectionStringName")] + public string ConnectionStringName { + get { return (string)this ["connectionStringName"]; } + set { this ["connectionStringName"] = value; } + } + + [ConfigurationProperty("description")] + public string Description { + get { return (string)this ["description"]; } + set { this ["description"] = value; } + } + + [ConfigurationProperty("applicationName")] + public string ApplicationName { + get { return (string)this ["applicationName"]; } + set { this ["applicationName"] = value; } + } + } +} diff --git a/NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationCollection.cs b/NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationCollection.cs new file mode 100644 index 00000000..14b65694 --- /dev/null +++ b/NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationCollection.cs @@ -0,0 +1,26 @@ +using System; +using System.Configuration; +using System.ComponentModel; + +namespace Npgsql.Web.Blog.Configuration +{ + public class BlogProvidersConfigurationCollection : ConfigurationElementCollection + { + protected override ConfigurationElement CreateNewElement () + { + return new BlogProviderConfigurationElement(); + } + + protected override object GetElementKey (ConfigurationElement element) + { + return ((BlogProviderConfigurationElement) element).Name; + } + + public BlogProviderConfigurationElement GetElement (string name) + { + return this.BaseGet(name) as BlogProviderConfigurationElement; + } + } + +} + diff --git a/NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationSection.cs b/NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationSection.cs new file mode 100644 index 00000000..96800d86 --- /dev/null +++ b/NpgsqlBlogProvider/Configuration/BlogProvidersConfigurationSection.cs @@ -0,0 +1,26 @@ +using System; +using System.Configuration; +using System.ComponentModel; + +namespace Npgsql.Web.Blog.Configuration +{ + public class BlogProvidersConfigurationSection : ConfigurationSection + { + [ConfigurationProperty("defaultProvider")] + public string DefaultProvider { + get { return (string)base ["defaultProvider"]; } + set { base ["defaultProvider"] = value; } + } + + [ConfigurationProperty("providers")] + [ConfigurationCollection(typeof(BlogProvidersConfigurationCollection), + AddItemName = "add", + ClearItemsName = "clear", + RemoveItemName = "remove")] + public BlogProvidersConfigurationCollection Providers{ + get { return (BlogProvidersConfigurationCollection) base ["providers"]; } + set { base ["providers"] = value; } + } + } + +} diff --git a/NpgsqlBlogProvider/DataModel/Blog.cs b/NpgsqlBlogProvider/DataModel/Blog.cs new file mode 100644 index 00000000..74c6590e --- /dev/null +++ b/NpgsqlBlogProvider/DataModel/Blog.cs @@ -0,0 +1,26 @@ +using System; +using System.Configuration; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel; + +namespace Npgsql.Web.Blog.DataModel +{ + public class Blog + { + string title; + + [StringValidator(MaxLength=512)] + [Required] + [DisplayName("Titre")] + public string Title { + get { + return title; + } + set { + title = value; + } + } + + } +} + diff --git a/NpgsqlBlogProvider/DataModel/BlogEntry.cs b/NpgsqlBlogProvider/DataModel/BlogEntry.cs new file mode 100644 index 00000000..c58a632c --- /dev/null +++ b/NpgsqlBlogProvider/DataModel/BlogEntry.cs @@ -0,0 +1,91 @@ +using System; +using System.Configuration; +using System.Configuration.Provider; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Npgsql.Web.Blog.DataModel +{ + public class BlogEntry + { + long id; + [DisplayName("Identifiant numérique de billet")] + public long Id { + get { + return id; + } + set { + id = value; + } + } + + string title; + + [StringValidator(MaxLength=512)] + [DisplayName("Titre du billet")] + [StringLength(512)] + [RegularExpression("^[^:%&?]*$",ErrorMessage = "Les caratères suivants sont invalides pour un titre: :%&?")] + [Required(ErrorMessage = "S'il vous plait, saisissez un titre")] + public string Title { + get { + return title; + } + set { + title = value; + } + } + + string content; + + [DisplayName("Corps du billet")] + [Required(ErrorMessage = "S'il vous plait, saisissez un texte.")] + public string Content { + get { + return content; + } + set { + content = value; + } + } + + string userName; + + [StringValidator(MaxLength=255)] + [DisplayName("Nom de l'auteur")] + public string UserName { + get { + return userName; + } + set { + userName = value; + } + } + + public DateTime posted; + + [DisplayName("Date de creation")] + public DateTime Posted { + get { + return posted; + } + set { + posted = value; + } + } + + public DateTime modified; + + [DisplayName("Date de modification")] + public DateTime Modified { + get { + return modified; + } + set { + modified = value; + } + } + public bool Visible { get; set ; } + public string [] Tags { get; set ; } + } + +} diff --git a/NpgsqlBlogProvider/DataModel/BlogEntryCollection.cs b/NpgsqlBlogProvider/DataModel/BlogEntryCollection.cs new file mode 100644 index 00000000..5e508cb1 --- /dev/null +++ b/NpgsqlBlogProvider/DataModel/BlogEntryCollection.cs @@ -0,0 +1,12 @@ +using System; +using System.Configuration; +using System.Configuration.Provider; +using System.Collections.Generic; + +namespace Npgsql.Web.Blog.DataModel +{ + public class BlogEntryCollection : List + { + } + +} diff --git a/NpgsqlBlogProvider/DataModel/Comment.cs b/NpgsqlBlogProvider/DataModel/Comment.cs new file mode 100644 index 00000000..698490dc --- /dev/null +++ b/NpgsqlBlogProvider/DataModel/Comment.cs @@ -0,0 +1,76 @@ +using System; +using System.Configuration; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Npgsql.Web.Blog.DataModel +{ + public class Comment + { + long id; + [DisplayName("Identifiant numérique de commentaire")] + public long Id { + get { + return id; + } + set { + id = value; + } + } + long postid; + [DisplayName("Identifiant numérique du billet commenté")] + public long PostId { + get { + return postid; + } + set { + postid = value; + } + } + /// + /// Gets or sets the author of this comment. + /// + /// From. + public string From { get; set; } + + string content; + [DisplayName("Contenu")] + [Required(ErrorMessage = "S'il vous plait, saisissez un contenu")] + public string CommentText { + get { + return content; + } + set { + content = value; + } + } + + public DateTime posted; + + [DisplayName("Date de creation")] + public DateTime Posted { + get { + return posted; + } + set { + posted = value; + } + } + + public DateTime modified; + + [DisplayName("Date de modification")] + public DateTime Modified { + get { + return modified; + } + set { + modified = value; + } + } + + public bool Visible { get; set ; } + + } +} + diff --git a/NpgsqlBlogProvider/DataModel/FindBlogEntryFlags.cs b/NpgsqlBlogProvider/DataModel/FindBlogEntryFlags.cs new file mode 100644 index 00000000..43dff0f9 --- /dev/null +++ b/NpgsqlBlogProvider/DataModel/FindBlogEntryFlags.cs @@ -0,0 +1,16 @@ +using System; +using System.Configuration; +using System.Configuration.Provider; +using System.Collections.Generic; + +namespace Npgsql.Web.Blog.DataModel +{ + + public enum FindBlogEntryFlags : byte { + MatchTitle = 1, + MatchContent = 2, + MatchUserName = 4, + MatchInvisible = 8 + } + +} diff --git a/NpgsqlBlogProvider/NpgsqlBlogProvider.cs b/NpgsqlBlogProvider/NpgsqlBlogProvider.cs new file mode 100644 index 00000000..cf811139 --- /dev/null +++ b/NpgsqlBlogProvider/NpgsqlBlogProvider.cs @@ -0,0 +1,340 @@ +using System; +using System.Configuration; +using System.Configuration.Provider; +using Npgsql; +using Npgsql.Web.Blog.DataModel; +using System.Collections.Generic; + +namespace Npgsql.Web.Blog +{ + public class NpgsqlBlogProvider : BlogProvider + { + string applicationName; + string connectionString; + + #region implemented abstract members of BlogProvider + + public override long GetPostId (string username, string title) + { + throw new NotImplementedException (); + } + public override Comment[] GetComments (long postid, bool getHidden) + { + List cmts = new List (); + + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + + cmd.CommandText = "select _id, username, bcontent, modified, posted, visible from comment " + + "where applicationname = @appname and postid = @id" + + ((getHidden) ? " and visible = true ":" ") + + "order by posted asc" ; + cmd.Parameters.Add ("@appname", applicationName); + cmd.Parameters.Add ("@id", postid); + cnx.Open (); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) { + while (rdr.Read ()) { + Comment c = new Comment(); + c.CommentText = rdr.GetString (rdr.GetOrdinal ("bcontent")); + c.From = rdr.GetString (rdr.GetOrdinal ("username")); + c.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified")); + c.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted")); + c.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible")); + c.PostId = postid; + c.Id = rdr.GetInt64(rdr.GetOrdinal("_id")); + cmts.Add (c); + } + } + } + return cmts.ToArray(); + } + public override void UpdatePost (long postid, string content, bool visible) + { + using (NpgsqlConnection cnx = new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + DateTime now = DateTime.Now; + cmd.CommandText = + "update blog set modified=@now, bcontent=@content, " + + "visible = @visible where _id = @id"; + cmd.Parameters.Add ("@now", now); + cmd.Parameters.Add ("@content", content); + cmd.Parameters.Add ("@visible", visible); + cmd.Parameters.Add ("@id", postid); + cnx.Open (); + cmd.ExecuteNonQuery (); + cnx.Close(); + } + } + + public override void RemovePost (long postid) + { + throw new NotImplementedException (); + } + + public override long Comment (string from, long postid, string content) + { + if (from == null) + throw new ArgumentNullException("from"); + if (content == null) + throw new ArgumentNullException("content"); + bool visible = AutoValidateComment; + using (NpgsqlConnection cnx= + new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "insert into comment (postid,bcontent," + + "modified,posted,visible,username,applicationname)" + + "values (@postid,@bcontent,@modified,@posted," + + "@visible,@username,@appname) returning _id"; + cmd.Parameters.Add ("@postid", postid); + cmd.Parameters.Add ("@bcontent", content); + DateTime now = DateTime.Now; + cmd.Parameters.Add ("@modified", now); + cmd.Parameters.Add ("@posted", now); + cmd.Parameters.Add ("@visible", visible); + cmd.Parameters.Add ("@username", from); + cmd.Parameters.Add ("@appname", applicationName); + cnx.Open (); + return (long) cmd.ExecuteScalar(); + } + } + + public override void ValidateComment (long cmtid) + { + throw new NotImplementedException (); + } + + public override void UpdateComment + (long cmtid, string content, bool visible) + { + throw new NotImplementedException (); + } + + private bool autoValidateComment = true; + + public override bool AutoValidateComment { + get { + return autoValidateComment; + } + set { + autoValidateComment=value; + } + } + + + public override string BlogTitle + (string username) + { + throw new NotImplementedException (); + } + + #endregion + + public override void Initialize + (string name, System.Collections.Specialized.NameValueCollection config) + { + string cnxName = config ["connectionStringName"]; + connectionString = ConfigurationManager.ConnectionStrings [cnxName].ConnectionString; + config.Remove ("connectionStringName"); + applicationName = config ["applicationName"]; + config.Remove ("applicationName"); + defaultPageSize = int.Parse ( config ["pageLen"] ?? "10") ; + base.Initialize (name, config); + } + #region implemented abstract members of BlogProvider + public override BlogEntry GetPost (long postid) + { + BlogEntry be = null; + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "select username, title, bcontent, modified, posted, visible from blog " + + "where applicationname = @appname and _id = @id"; + cmd.Parameters.Add ("@appname", applicationName); + cmd.Parameters.Add ("@id", postid); + cnx.Open (); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) { + if (rdr.Read ()) { + be = new BlogEntry (); + be.Title = rdr.GetString (rdr.GetOrdinal ("title")); + be.Content = rdr.GetString (rdr.GetOrdinal ("bcontent")); + be.UserName = rdr.GetString (rdr.GetOrdinal ("username")); + be.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified")); + be.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted")); + be.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible")); + be.Id = postid; + } + } + } + return be; + } + public override long RemoveComment (long cmtid) + { + long postid = 0; + using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand ()) { + cmd.CommandText = "delete from comment where _id = @id returning postid"; + cmd.Parameters.Add ("id", cmtid); + cnx.Open (); + postid = (long) cmd.ExecuteScalar (); + } + return postid; + } + public override BlogEntry GetPost (string username, string title) + { + BlogEntry be = null; + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "select _id,bcontent,modified,posted,visible from blog " + + "where applicationname = @appname and username = @username and title = @title"; + cmd.Parameters.Add ("@appname", applicationName); + cmd.Parameters.Add ("@username", username); + cmd.Parameters.Add ("@title", title); + cnx.Open (); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) { + if (rdr.Read ()) { + be = new BlogEntry (); + be.Title = title; + be.Content = rdr.GetString (rdr.GetOrdinal ("bcontent")); + be.UserName = username; + be.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified")); + be.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted")); + be.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible")); + be.Id = rdr.GetInt64 (rdr.GetOrdinal ("_id")); + } + } + } + return be; + } + + public override long Post (string username, string title, string content, bool visible) + { + if (username == null) + throw new ArgumentNullException("username"); + if (title == null) + throw new ArgumentNullException("title"); + if (content == null) + throw new ArgumentNullException("content"); + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "insert into blog (title,bcontent,modified,posted,visible,username,applicationname)" + + "values (@title,@bcontent,@modified,@posted,@visible,@username,@appname) returning _id"; + cmd.Parameters.Add ("@title", title); + cmd.Parameters.Add ("@bcontent", content); + DateTime now = DateTime.Now; + cmd.Parameters.Add ("@modified", now); + cmd.Parameters.Add ("@posted", now); + cmd.Parameters.Add ("@visible", visible); + cmd.Parameters.Add ("@username", username); + cmd.Parameters.Add ("@appname", applicationName); + cnx.Open (); + return (long) cmd.ExecuteScalar(); + } + } + + public override BlogEntryCollection FindPost (string pattern, FindBlogEntryFlags searchflags, int pageIndex, int pageSize, out int totalRecords) + { + BlogEntryCollection c = new BlogEntryCollection (); + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "select title,bcontent,modified,posted,username,visible from blog " + + "where applicationname = @appname"; + cmd.Parameters.Add ("@appname", applicationName); + if ((searchflags & FindBlogEntryFlags.MatchContent) > 0) { + cmd.CommandText += " and bcontent like @bcontent"; + cmd.Parameters.Add ("@bcontent", pattern); + } + if ((searchflags & FindBlogEntryFlags.MatchTitle) > 0) { + cmd.CommandText += " and title like @title"; + cmd.Parameters.Add ("@title", pattern); + } + if ((searchflags & FindBlogEntryFlags.MatchUserName) > 0) { + cmd.CommandText += " and username like @username"; + cmd.Parameters.Add ("@username", pattern); + } + if ((searchflags & FindBlogEntryFlags.MatchInvisible) == 0) { + cmd.CommandText += " and visible = true"; + } + + cmd.CommandText += " order by posted desc"; + cnx.Open (); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) { + totalRecords = 0; + int firstrec = pageIndex * pageSize; + int lastrec = firstrec + pageSize - 1; + while (rdr.Read()) { + if (totalRecords >= firstrec && totalRecords <= lastrec) { + BlogEntry be = new BlogEntry (); + be.Title = rdr.GetString (rdr.GetOrdinal ("title")); + be.Content = rdr.GetString (rdr.GetOrdinal ("bcontent")); + be.UserName = rdr.GetString (rdr.GetOrdinal ("username")); + be.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted")); + be.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified")); + be.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible")); + c.Add (be); + } + totalRecords++; + } + } + } + return c; + } + + public override void RemovePost (string username, string title) + { + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "delete from blog where username = @username and applicationname = @appname and title=@title"; + cmd.Parameters.Add ("@username",username); + cmd.Parameters.Add ("@appname", applicationName); + cmd.Parameters.Add ("@title",title); + cnx.Open (); + cmd.ExecuteNonQuery (); + cnx.Close(); + } + } + + + int defaultPageSize = 10; + + public override BlogEntryCollection LastPosts(int pageIndex, int pageSize, out int totalRecords) + { + BlogEntryCollection c = new BlogEntryCollection (); + using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + + /*cmd.CommandText = "select blog.* from blog, " + + "(select max(posted) lpost, username " + + "from blog where applicationname = @appname " + + "group by username) as lblog " + + "where blog.posted = lblog.lpost and blog.username = lblog.username " ; + */ + cmd.CommandText = "select * " + + "from blog where applicationname = @appname and visible = true " + + " order by posted desc limit @len" ; + + cmd.Parameters.Add ("@appname", applicationName); + cmd.Parameters.Add ("@len", defaultPageSize); + cnx.Open (); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) { + totalRecords = 0; + int firstrec = pageIndex * pageSize; + int lastrec = firstrec + pageSize - 1; + while (rdr.Read()) { + if (totalRecords >= firstrec && totalRecords <= lastrec) { + BlogEntry be = new BlogEntry (); + be.Title = rdr.GetString (rdr.GetOrdinal ("title")); + be.Content = rdr.GetString (rdr.GetOrdinal ("bcontent")); + be.UserName = rdr.GetString (rdr.GetOrdinal ("username")); + be.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted")); + be.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified")); + be.Visible = true; // because of sql code used + c.Add (be); + } + totalRecords++; + } + } + } + return c; + } + #endregion + } +} diff --git a/NpgsqlBlogProvider/NpgsqlBlogProvider.csproj b/NpgsqlBlogProvider/NpgsqlBlogProvider.csproj new file mode 100644 index 00000000..41bd272a --- /dev/null +++ b/NpgsqlBlogProvider/NpgsqlBlogProvider.csproj @@ -0,0 +1,70 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {C6E9E91B-97D3-48D9-8AA7-05356929E162} + Library + Npgsql.Web.Blog + NpgsqlBlogProvider + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + none + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NpgsqlBlogProvider/Sql/BlogTable.sql b/NpgsqlBlogProvider/Sql/BlogTable.sql new file mode 100644 index 00000000..07fc24e2 --- /dev/null +++ b/NpgsqlBlogProvider/Sql/BlogTable.sql @@ -0,0 +1,21 @@ + +-- Table: blog + +-- DROP TABLE blog; + +CREATE TABLE blog +( + applicationname character varying(255) NOT NULL, + username character varying(255) NOT NULL, + posted timestamp with time zone NOT NULL, + modified timestamp with time zone NOT NULL, + title character varying(255) NOT NULL, + bcontent text NOT NULL, + CONSTRAINT pk_blog PRIMARY KEY (username , applicationname , title ), + CONSTRAINT bloguser FOREIGN KEY (applicationname, username) + REFERENCES users (applicationname, username) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE +) +WITH ( + OIDS=FALSE +); diff --git a/NpgsqlMRPProviders/AssemblyInfo.cs b/NpgsqlMRPProviders/AssemblyInfo.cs new file mode 100644 index 00000000..5aad255b --- /dev/null +++ b/NpgsqlMRPProviders/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("NpgsqlMRPProviders")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("paul")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/NpgsqlMRPProviders/NpgsqlMRPProviders.csproj b/NpgsqlMRPProviders/NpgsqlMRPProviders.csproj new file mode 100644 index 00000000..797f8539 --- /dev/null +++ b/NpgsqlMRPProviders/NpgsqlMRPProviders.csproj @@ -0,0 +1,68 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {BBA7175D-7F92-4278-96FC-84C495A2B5A6} + Library + Npgsql.Web + NpgsqlMRPProviders + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + none + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NpgsqlMRPProviders/NpgsqlMembershipProvider.cs b/NpgsqlMRPProviders/NpgsqlMembershipProvider.cs new file mode 100644 index 00000000..bce01049 --- /dev/null +++ b/NpgsqlMRPProviders/NpgsqlMembershipProvider.cs @@ -0,0 +1,1211 @@ +using System.Web.Security; +using System.Configuration.Provider; +using System.Collections.Specialized; +using System; +using System.Data; +using Npgsql; +using NpgsqlTypes; +using System.Configuration; +using System.Diagnostics; +using System.Web; +using System.Globalization; +using System.Security.Cryptography; +using System.Text; +using System.Web.Configuration; + +namespace Npgsql.Web +{ + public sealed class NpgsqlMembershipProvider: MembershipProvider + { + + // + // Global connection string, generated password length. + // + + private int newPasswordLength = 8; + private string connectionString; + + // + // Used when determining encryption key values. + // + + private MachineKeySection machineKey; + + // + // System.Configuration.Provider.ProviderBase.Initialize Method + // + + public override void Initialize (string name, NameValueCollection config) + { + // + // Initialize values from web.config. + // + + if (config == null) + throw new ArgumentNullException ("config"); + + if (name == null || name.Length == 0) + name = "NpgsqlMembershipProvider"; + + if (String.IsNullOrEmpty (config ["description"])) { + config.Remove ("description"); + config.Add ("description", "Sample Npgsql Membership provider"); + } + + // Initialize the abstract base class. + base.Initialize (name, config); + + pApplicationName = GetConfigValue (config ["applicationName"], + System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath); + pMaxInvalidPasswordAttempts = Convert.ToInt32 (GetConfigValue (config ["maxInvalidPasswordAttempts"], "5")); + pPasswordAttemptWindow = Convert.ToInt32 (GetConfigValue (config ["passwordAttemptWindow"], "10")); + pMinRequiredNonAlphanumericCharacters = Convert.ToInt32 (GetConfigValue (config ["minRequiredNonAlphanumericCharacters"], "1")); + pMinRequiredPasswordLength = Convert.ToInt32 (GetConfigValue (config ["minRequiredPasswordLength"], "7")); + pPasswordStrengthRegularExpression = Convert.ToString (GetConfigValue (config ["passwordStrengthRegularExpression"], "")); + pEnablePasswordReset = Convert.ToBoolean (GetConfigValue (config ["enablePasswordReset"], "true")); + pEnablePasswordRetrieval = Convert.ToBoolean (GetConfigValue (config ["enablePasswordRetrieval"], "true")); + pRequiresQuestionAndAnswer = Convert.ToBoolean (GetConfigValue (config ["requiresQuestionAndAnswer"], "false")); + pRequiresUniqueEmail = Convert.ToBoolean (GetConfigValue (config ["requiresUniqueEmail"], "true")); + string temp_format = config ["passwordFormat"]; + if (temp_format == null) { + temp_format = "Hashed"; + } + + switch (temp_format) { + case "Hashed": + pPasswordFormat = MembershipPasswordFormat.Hashed; + break; + case "Encrypted": + pPasswordFormat = MembershipPasswordFormat.Encrypted; + break; + case "Clear": + pPasswordFormat = MembershipPasswordFormat.Clear; + break; + default: + throw new ProviderException ("Password format not supported."); + } + + // + // Initialize NpgsqlConnection. + // + + ConnectionStringSettings ConnectionStringSettings = + ConfigurationManager.ConnectionStrings [config ["connectionStringName"]]; + + if (ConnectionStringSettings == null || ConnectionStringSettings.ConnectionString.Trim () == "") { + throw new ProviderException ("Connection string cannot be blank."); + } + connectionString = ConnectionStringSettings.ConnectionString; + + // Get encryption and decryption key information from the configuration. + Configuration cfg = + WebConfigurationManager.OpenWebConfiguration (System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath); + machineKey = (MachineKeySection)cfg.GetSection ("system.web/machineKey"); + + if (machineKey.ValidationKey.Contains ("AutoGenerate")) + if (PasswordFormat != MembershipPasswordFormat.Clear) + throw new ProviderException ("Hashed or Encrypted passwords " + + "are not supported with auto-generated keys." + ); + } + + + // + // A helper function to retrieve config values from the configuration file. + // + + private string GetConfigValue (string configValue, string defaultValue) + { + if (String.IsNullOrEmpty (configValue)) + return defaultValue; + + return configValue; + } + + + // + // System.Web.Security.MembershipProvider properties. + // + private string pApplicationName; + private bool pEnablePasswordReset; + private bool pEnablePasswordRetrieval; + private bool pRequiresQuestionAndAnswer; + private bool pRequiresUniqueEmail; + private int pMaxInvalidPasswordAttempts; + private int pPasswordAttemptWindow; + private MembershipPasswordFormat pPasswordFormat; + + public override string ApplicationName { + get { return pApplicationName; } + set { pApplicationName = value; } + } + + public override bool EnablePasswordReset { + get { return pEnablePasswordReset; } + } + + public override bool EnablePasswordRetrieval { + get { return pEnablePasswordRetrieval; } + } + + public override bool RequiresQuestionAndAnswer { + get { return pRequiresQuestionAndAnswer; } + } + + public override bool RequiresUniqueEmail { + get { return pRequiresUniqueEmail; } + } + + public override int MaxInvalidPasswordAttempts { + get { return pMaxInvalidPasswordAttempts; } + } + + public override int PasswordAttemptWindow { + get { return pPasswordAttemptWindow; } + } + + public override MembershipPasswordFormat PasswordFormat { + get { return pPasswordFormat; } + } + + private int pMinRequiredNonAlphanumericCharacters; + + public override int MinRequiredNonAlphanumericCharacters { + get { return pMinRequiredNonAlphanumericCharacters; } + } + + private int pMinRequiredPasswordLength; + + public override int MinRequiredPasswordLength { + get { return pMinRequiredPasswordLength; } + } + + private string pPasswordStrengthRegularExpression; + + public override string PasswordStrengthRegularExpression { + get { return pPasswordStrengthRegularExpression; } + } + + // + // System.Web.Security.MembershipProvider methods. + // + + // + // MembershipProvider.ChangePassword + // + + public override bool ChangePassword (string username, string oldPwd, string newPwd) + { + if (!ValidateUser (username, oldPwd)) + return false; + ValidatePasswordEventArgs args = new ValidatePasswordEventArgs (username, newPwd, true); + OnValidatingPassword (args); + if (args.Cancel) { + if (args.FailureInformation != null) + throw args.FailureInformation; + else + throw new MembershipPasswordException ("Change password canceled due to new password validation failure."); + } + int rowsAffected = 0; + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("UPDATE Users " + + " SET Passw = @Password, LastPasswordChangedDate = @LastPasswordChangedDate " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + cmd.Parameters.Add ("@Password", NpgsqlDbType.Varchar, 255).Value = EncodePassword (newPwd); + cmd.Parameters.Add ("@LastPasswordChangedDate", DateTime.Now); + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + rowsAffected = cmd.ExecuteNonQuery (); + conn.Close (); + } + } + if (rowsAffected > 0) { + return true; + } + + return false; + } + + + + // + // MembershipProvider.ChangePasswordQuestionAndAnswer + // + + public override bool ChangePasswordQuestionAndAnswer (string username, + string password, + string newPwdQuestion, + string newPwdAnswer) + { + if (!ValidateUser (username, password)) + return false; + int rowsAffected = 0; + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("UPDATE Users " + + " SET PasswordQuestion = @Question, PasswordAnswer = @Answer" + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + cmd.Parameters.Add ("@Question", NpgsqlDbType.Varchar, 255).Value = newPwdQuestion; + cmd.Parameters.Add ("@Answer", NpgsqlDbType.Varchar, 255).Value = EncodePassword (newPwdAnswer); + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + rowsAffected = cmd.ExecuteNonQuery (); + conn.Close (); + } + } + if (rowsAffected > 0) { + return true; + } + + return false; + } + + + + // + // MembershipProvider.CreateUser + // + + public override MembershipUser CreateUser (string username, + string password, + string email, + string passwordQuestion, + string passwordAnswer, + bool isApproved, + object providerUserKey, + out MembershipCreateStatus status) + { + ValidatePasswordEventArgs args = + new ValidatePasswordEventArgs (username, password, true); + + OnValidatingPassword (args); + + if (args.Cancel) { + status = MembershipCreateStatus.InvalidPassword; + return null; + } + if (RequiresUniqueEmail && GetUserNameByEmail (email) != "") { + status = MembershipCreateStatus.DuplicateEmail; + return null; + } + + MembershipUser u = GetUser (username, false); + + if (u == null) { + DateTime createDate = DateTime.Now; + + if (providerUserKey == null) { + providerUserKey = Guid.NewGuid (); + } else { + if (!(providerUserKey is Guid)) { + status = MembershipCreateStatus.InvalidProviderUserKey; + return null; + } + } + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("INSERT INTO Users " + + " (PKID, Username, Passw, Email, PasswordQuestion, " + + " PasswordAnswer, IsApproved," + + " Comment, CreationDate, LastPasswordChangedDate, LastActivityDate," + + " ApplicationName, IsLockedOut, LastLockedOutDate," + + " FailedPasswordAttemptCount, FailedPasswordAttemptWindowStart, " + + " FailedPasswordAnswerAttemptCount, FailedPasswordAnswerAttemptWindowStart)" + + " Values(@PKID, @Username, @Password, @Email, @PasswordQuestion, @PasswordAnswer, @IsApproved," + + "@Comment, @CreationDate, @LastPasswordChangedDate, @LastActivityDate, " + + "@ApplicationName,@IsLockedOut, @LastLockedOutDate," + + "@FailedPasswordAttemptCount , @FailedPasswordAttemptWindowStart, " + + " @FailedPasswordAnswerAttemptCount, @FailedPasswordAnswerAttemptWindowStart)", conn)) { + + cmd.Parameters.Add ("@PKID", NpgsqlDbType.Varchar).Value = providerUserKey; + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@Password", NpgsqlDbType.Varchar, 255).Value = EncodePassword (password); + cmd.Parameters.Add ("@Email", NpgsqlDbType.Varchar, 128).Value = email; + cmd.Parameters.Add ("@PasswordQuestion", NpgsqlDbType.Varchar, 255).Value = passwordQuestion; + cmd.Parameters.Add ("@PasswordAnswer", NpgsqlDbType.Varchar, 255).Value = EncodePassword (passwordAnswer); + cmd.Parameters.Add ("@IsApproved", NpgsqlDbType.Bit).Value = isApproved; + cmd.Parameters.Add ("@Comment", NpgsqlDbType.Varchar, 255).Value = ""; + cmd.Parameters.Add ("@CreationDate", createDate); + cmd.Parameters.Add ("@LastPasswordChangedDate", createDate); + cmd.Parameters.Add ("@LastActivityDate", createDate); + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + cmd.Parameters.Add ("@IsLockedOut", NpgsqlDbType.Bit).Value = false; + cmd.Parameters.Add ("@LastLockedOutDate", createDate); + cmd.Parameters.Add ("@FailedPasswordAttemptCount", NpgsqlDbType.Integer).Value = 0; + cmd.Parameters.Add ("@FailedPasswordAttemptWindowStart", createDate); + cmd.Parameters.Add ("@FailedPasswordAnswerAttemptCount", NpgsqlDbType.Integer).Value = 0; + cmd.Parameters.Add ("@FailedPasswordAnswerAttemptWindowStart", createDate); + conn.Open (); + int recAdded = cmd.ExecuteNonQuery (); + if (recAdded > 0) { + status = MembershipCreateStatus.Success; + } else { + status = MembershipCreateStatus.UserRejected; + } + conn.Close (); + } + } + return GetUser (username, false); + } else { + status = MembershipCreateStatus.DuplicateUserName; + } + return null; + } + + // + // MembershipProvider.DeleteUser + // + /// + /// To be added. + /// + /// + /// Delete the user from given name. + /// + /// + /// The deleteAllRelatedData parameter usage has to be implemented. + /// + /// + /// The user. + /// + /// + /// If set to true username. + /// + /// + /// If set to true delete all related data. + /// + public override bool DeleteUser (string username, bool deleteAllRelatedData) + { + int rowsAffected = 0; + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("DELETE FROM Users " + + " WHERE Username = @Username AND Applicationname = @ApplicationName", conn)) { + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + rowsAffected = cmd.ExecuteNonQuery (); + if (deleteAllRelatedData) { + // TODO Process commands to delete all data for the user in the database. + } + conn.Close (); + } + } + return (rowsAffected > 0); + } + + // + // MembershipProvider.GetAllUsers + // + + public override MembershipUserCollection GetAllUsers (int pageIndex, int pageSize, out int totalRecords) + { + MembershipUserCollection users = new MembershipUserCollection (); + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT Count(*) FROM Users " + + "WHERE ApplicationName = @ApplicationName", conn)) { + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = ApplicationName; + conn.Open (); + totalRecords = 0; + totalRecords = (int)((long)cmd.ExecuteScalar ()); + + if (totalRecords > 0) { + cmd.CommandText = "SELECT PKID, Username, Email, PasswordQuestion," + + " Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate," + + " LastActivityDate, LastPasswordChangedDate, LastLockedOutDate" + + " FROM Users " + + " WHERE ApplicationName = @ApplicationName " + + " ORDER BY Username Asc"; + using (NpgsqlDataReader reader = cmd.ExecuteReader ()) { + + int counter = 0; + int startIndex = pageSize * pageIndex; + int endIndex = startIndex + pageSize - 1; + + while (reader.Read()) { + if (counter >= startIndex) { + MembershipUser u = GetUserFromReader (reader); + users.Add (u); + } + + if (counter >= endIndex) { + cmd.Cancel (); + } + + counter++; + } + reader.Close (); + + } + } + conn.Close (); + } + } + return users; + } + + + // + // MembershipProvider.GetNumberOfUsersOnline + // + + public override int GetNumberOfUsersOnline () + { + int numOnline = 0; + TimeSpan onlineSpan = new TimeSpan (0, System.Web.Security.Membership.UserIsOnlineTimeWindow, 0); + DateTime compareTime = DateTime.Now.Subtract (onlineSpan); + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT Count(*) FROM Users " + + " WHERE LastActivityDate > @CompareDate AND ApplicationName = @ApplicationName", conn)) { + + cmd.Parameters.Add ("@CompareDate", compareTime); + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + + + conn.Open (); + + numOnline = (int)cmd.ExecuteScalar (); + } + conn.Close (); + } + + return numOnline; + } + + + + // + // MembershipProvider.GetPassword + // + + public override string GetPassword (string username, string answer) + { + string password = ""; + string passwordAnswer = ""; + + if (!EnablePasswordRetrieval) { + throw new ProviderException ("Password Retrieval Not Enabled."); + } + + if (PasswordFormat == MembershipPasswordFormat.Hashed) { + throw new ProviderException ("Cannot retrieve Hashed passwords."); + } + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT Passw, PasswordAnswer, IsLockedOut FROM Users " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + + NpgsqlDataReader reader = null; + + + conn.Open (); + + using (reader = cmd.ExecuteReader ()) { + + if (reader.HasRows) { + reader.Read (); + + if (reader.GetBoolean (2)) + throw new MembershipPasswordException ("The supplied user is locked out."); + + password = reader.GetString (0); + passwordAnswer = reader.GetString (1); + } else { + throw new MembershipPasswordException ("The supplied user name is not found."); + } + + reader.Close (); + } + } + conn.Close (); + } + + if (RequiresQuestionAndAnswer && !CheckPassword (answer, passwordAnswer)) { + UpdateFailureCount (username, "passwordAnswer"); + throw new MembershipPasswordException ("Incorrect password answer."); + } + if (PasswordFormat == MembershipPasswordFormat.Encrypted) { + password = UnEncodePassword (password); + } + return password; + } + + // + // MembershipProvider.GetUser(string, bool) + // + /// + /// Gets the user as a MembershipUser object + /// + /// + /// The user. + /// + /// + /// The user name to search. + /// + /// + /// Only return the user when it's online. + /// + public override MembershipUser GetUser (string username, bool userIsOnline) + { + MembershipUser u = null; + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT PKID, Username, Email, PasswordQuestion," + + " Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate," + + " LastActivityDate, LastPasswordChangedDate, LastLockedOutDate" + + " FROM Users WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + using (NpgsqlDataReader reader = cmd.ExecuteReader ()) { + if (reader.HasRows) { + reader.Read (); + u = GetUserFromReader (reader); + + if (userIsOnline) { + NpgsqlCommand updateCmd = new NpgsqlCommand ("UPDATE Users " + + "SET LastActivityDate = @LastActivityDate " + + "WHERE Username = @Username AND Applicationname = @ApplicationName", conn); + + updateCmd.Parameters.Add ("@LastActivityDate", DateTime.Now); + updateCmd.Parameters.Add ("@Username", username); + updateCmd.Parameters.Add ("@ApplicationName", pApplicationName); + + updateCmd.ExecuteNonQuery (); + } + } + reader.Close (); + } + } + conn.Close (); + } + return u; + } + + + // + // MembershipProvider.GetUser(object, bool) + // + public override MembershipUser GetUser (object providerUserKey, bool userIsOnline) + { + MembershipUser u = null; + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT PKID, Username, Email, PasswordQuestion," + + " Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate," + + " LastActivityDate, LastPasswordChangedDate, LastLockedOutDate" + + " FROM Users WHERE PKID = @PKID", conn)) { + + cmd.Parameters.Add ("@PKID", NpgsqlDbType.Varchar).Value = providerUserKey; + conn.Open (); + + using (NpgsqlDataReader reader = cmd.ExecuteReader ()) { + if (reader.HasRows) { + reader.Read (); + u = GetUserFromReader (reader); + + if (userIsOnline) { + NpgsqlCommand updateCmd = new NpgsqlCommand ("UPDATE Users " + + "SET LastActivityDate = @LastActivityDate " + + "WHERE PKID = @PKID", conn); + updateCmd.Parameters.Add ("@LastActivityDate", DateTime.Now); + updateCmd.Parameters.Add ("@PKID", providerUserKey); + updateCmd.ExecuteNonQuery (); + } + } + reader.Close (); + } + } + conn.Close (); + } + + return u; + } + + + // + // GetUserFromReader + // A helper function that takes the current row from the NpgsqlDataReader + // and hydrates a MembershiUser from the values. Called by the + // MembershipUser.GetUser implementation. + // + + private MembershipUser GetUserFromReader (NpgsqlDataReader reader) + { + object providerUserKey = reader.GetValue (0); + string username = reader.GetString (1); + string email = reader.GetString (2); + + string passwordQuestion = ""; + if (reader.GetValue (3) != DBNull.Value) + passwordQuestion = reader.GetString (3); + + string comment = ""; + if (reader.GetValue (4) != DBNull.Value) + comment = reader.GetString (4); + + bool isApproved = reader.GetBoolean (5); + bool isLockedOut = reader.GetBoolean (6); + DateTime creationDate = reader.GetDateTime (7); + + DateTime lastLoginDate = new DateTime (); + if (reader.GetValue (8) != DBNull.Value) + lastLoginDate = reader.GetDateTime (8); + + DateTime lastActivityDate = reader.GetDateTime (9); + DateTime lastPasswordChangedDate = reader.GetDateTime (10); + + DateTime lastLockedOutDate = new DateTime (); + if (reader.GetValue (11) != DBNull.Value) + lastLockedOutDate = reader.GetDateTime (11); + + MembershipUser u = new MembershipUser (this.Name, + username, + providerUserKey, + email, + passwordQuestion, + comment, + isApproved, + isLockedOut, + creationDate, + lastLoginDate, + lastActivityDate, + lastPasswordChangedDate, + lastLockedOutDate); + + return u; + } + + + // + // MembershipProvider.UnlockUser + // + + public override bool UnlockUser (string username) + { + int rowsAffected = 0; + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("UPDATE Users " + + " SET IsLockedOut = False, LastLockedOutDate = @LastLockedOutDate " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + cmd.Parameters.Add ("@LastLockedOutDate", DateTime.Now); + cmd.Parameters.Add ("@Username", username); + cmd.Parameters.Add ("@ApplicationName", pApplicationName); + conn.Open (); + rowsAffected = cmd.ExecuteNonQuery (); + conn.Close (); + } + } + if (rowsAffected > 0) + return true; + + return false; + } + + + // + // MembershipProvider.GetUserNameByEmail + // + + public override string GetUserNameByEmail (string email) + { + string username = ""; + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT Username" + + " FROM Users WHERE Email = @Email AND ApplicationName = @ApplicationName", conn)) { + cmd.Parameters.Add ("@Email", NpgsqlDbType.Varchar, 128).Value = email; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + username = (string)cmd.ExecuteScalar (); + conn.Close (); + } + } + if (username == null) + username = ""; + return username; + } + + // + // MembershipProvider.ResetPassword + // + + public override string ResetPassword (string username, string answer) + { + int rowsAffected = 0; + if (!EnablePasswordReset) { + throw new NotSupportedException ("Password reset is not enabled."); + } + + if (answer == null && RequiresQuestionAndAnswer) { + UpdateFailureCount (username, "passwordAnswer"); + throw new ProviderException ("Password answer required for password reset."); + } + + string newPassword = + System.Web.Security.Membership.GeneratePassword (newPasswordLength, MinRequiredNonAlphanumericCharacters); + + ValidatePasswordEventArgs args = new ValidatePasswordEventArgs (username, newPassword, true); + + OnValidatingPassword (args); + + if (args.Cancel) + if (args.FailureInformation != null) + throw args.FailureInformation; + else + throw new MembershipPasswordException ("Reset password canceled due to password validation failure."); + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT PasswordAnswer, IsLockedOut FROM Users " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + + string passwordAnswer = ""; + conn.Open (); + + using (NpgsqlDataReader reader = cmd.ExecuteReader (CommandBehavior.SingleRow)) { + + if (reader.HasRows) { + reader.Read (); + + if (reader.GetBoolean (1)) + throw new MembershipPasswordException ("The supplied user is locked out."); + + passwordAnswer = reader.GetString (0); + } else { + throw new MembershipPasswordException ("The supplied user name is not found."); + } + + if (RequiresQuestionAndAnswer && !CheckPassword (answer, passwordAnswer)) { + UpdateFailureCount (username, "passwordAnswer"); + + throw new MembershipPasswordException ("Incorrect password answer."); + } + + NpgsqlCommand updateCmd = new NpgsqlCommand ("UPDATE Users " + + " SET Passw = @Password, LastPasswordChangedDate = @LastPasswordChangedDate" + + " WHERE Username = @Username AND ApplicationName = @ApplicationName AND IsLockedOut = False", conn); + + updateCmd.Parameters.Add ("@Password", NpgsqlDbType.Varchar, 255).Value = EncodePassword (newPassword); + updateCmd.Parameters.Add ("@LastPasswordChangedDate", DateTime.Now); + updateCmd.Parameters.Add ("@Username", username); + updateCmd.Parameters.Add ("@ApplicationName", pApplicationName); + + rowsAffected = updateCmd.ExecuteNonQuery (); + + reader.Close (); + } + conn.Close (); + } + } + + if (rowsAffected > 0) { + return newPassword; + } else { + throw new MembershipPasswordException ("User not found, or user is locked out. Password not Reset."); + } + } + + + // + // MembershipProvider.UpdateUser + // + + public override void UpdateUser (MembershipUser user) + { + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("UPDATE Users " + + " SET Email = @Email, Comment = @Comment," + + " IsApproved = @IsApproved" + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + cmd.Parameters.Add ("@Email", NpgsqlDbType.Varchar, 128).Value = user.Email; + cmd.Parameters.Add ("@Comment", NpgsqlDbType.Varchar, 255).Value = user.Comment; + cmd.Parameters.Add ("@IsApproved", NpgsqlDbType.Bit).Value = user.IsApproved; + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = user.UserName; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + cmd.ExecuteNonQuery (); + conn.Close (); + } + } + } + + + // + // MembershipProvider.ValidateUser + // + + public override bool ValidateUser (string username, string password) + { + bool isValid = false; + + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT Passw, IsApproved FROM Users " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName AND IsLockedOut = False", conn)) { + + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + + bool isApproved = false; + string pwd = ""; + + conn.Open (); + bool userfound = false; + using (NpgsqlDataReader reader = cmd.ExecuteReader (CommandBehavior.SingleRow)) { + userfound = reader.HasRows; + if (userfound) { + reader.Read (); + pwd = reader.GetString (0); + isApproved = reader.GetBoolean (1); + } + + reader.Close (); + } + if (userfound) { + if (CheckPassword (password, pwd)) { + if (isApproved) { + isValid = true; + + NpgsqlCommand updateCmd = new NpgsqlCommand ("UPDATE Users SET LastLoginDate = @LastLoginDate" + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn); + + updateCmd.Parameters.Add ("@LastLoginDate", DateTime.Now); + updateCmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + updateCmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + updateCmd.ExecuteNonQuery (); + } + } else { + UpdateFailureCount (username, "password"); + } + } + conn.Close (); + } + } + + return isValid; + } + + + + /// + /// A helper method that performs the checks and updates associated with + /// password failure tracking. + /// + /// + /// User name. + /// + /// + /// Failure type, one of password, passwordAnswer + /// + private void UpdateFailureCount (string username, string failureType) + { + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT FailedPasswordAttemptCount, " + + " FailedPasswordAttemptWindowStart, " + + " FailedPasswordAnswerAttemptCount, " + + " FailedPasswordAnswerAttemptWindowStart " + + " FROM Users " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName", conn)) { + + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + + DateTime windowStart = new DateTime (); + int failureCount = 0; + + + conn.Open (); + using (NpgsqlDataReader reader = cmd.ExecuteReader (CommandBehavior.SingleRow)) { + + if (reader.HasRows) { + reader.Read (); + + if (failureType == "password") { + failureCount = reader.GetInt32 (0); + windowStart = reader.GetDateTime (1); + } + + if (failureType == "passwordAnswer") { + failureCount = reader.GetInt32 (2); + windowStart = reader.GetDateTime (3); + } + } + + reader.Close (); + } + DateTime windowEnd = windowStart.AddMinutes (PasswordAttemptWindow); + + if (failureCount == 0 || DateTime.Now > windowEnd) { + // First password failure or outside of PasswordAttemptWindow. + // Start a new password failure count from 1 and a new window starting now. + + if (failureType == "password") + cmd.CommandText = "UPDATE Users " + + " SET FailedPasswordAttemptCount = @Count, " + + " FailedPasswordAttemptWindowStart = @WindowStart " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName"; + + if (failureType == "passwordAnswer") + cmd.CommandText = "UPDATE Users " + + " SET FailedPasswordAnswerAttemptCount = @Count, " + + " FailedPasswordAnswerAttemptWindowStart = @WindowStart " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName"; + + cmd.Parameters.Clear (); + + cmd.Parameters.Add ("@Count", NpgsqlDbType.Integer).Value = 1; + cmd.Parameters.Add ("@WindowStart", DateTime.Now); + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + cmd.ExecuteNonQuery (); + + } else { + if (failureCount++ >= MaxInvalidPasswordAttempts) { + // Password attempts have exceeded the failure threshold. Lock out + // the user. + + cmd.CommandText = "UPDATE Users " + + " SET IsLockedOut = @IsLockedOut, LastLockedOutDate = @LastLockedOutDate " + + " WHERE Username = @Username AND ApplicationName = @ApplicationName"; + + cmd.Parameters.Clear (); + + cmd.Parameters.Add ("@IsLockedOut", NpgsqlDbType.Bit).Value = true; + cmd.Parameters.Add ("@LastLockedOutDate", DateTime.Now); + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + cmd.ExecuteNonQuery (); + + } else { + // Password attempts have not exceeded the failure threshold. Update + // the failure counts. Leave the window the same. + + if (failureType == "password") + cmd.CommandText = "UPDATE Users " + + " SET FailedPasswordAttemptCount = @Count" + + " WHERE Username = @Username AND ApplicationName = @ApplicationName"; + + if (failureType == "passwordAnswer") + cmd.CommandText = "UPDATE Users " + + " SET FailedPasswordAnswerAttemptCount = @Count" + + " WHERE Username = @Username AND ApplicationName = @ApplicationName"; + + cmd.Parameters.Clear (); + + cmd.Parameters.Add ("@Count", NpgsqlDbType.Integer).Value = failureCount; + cmd.Parameters.Add ("@Username", NpgsqlDbType.Varchar, 255).Value = username; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + + cmd.ExecuteNonQuery (); + } + } + } + conn.Close (); + } + } + + + // + // CheckPassword + // Compares password values based on the MembershipPasswordFormat. + // + + private bool CheckPassword (string password, string dbpassword) + { + string pass1 = password; + string pass2 = dbpassword; + + switch (PasswordFormat) { + case MembershipPasswordFormat.Encrypted: + pass2 = UnEncodePassword (dbpassword); + break; + case MembershipPasswordFormat.Hashed: + pass1 = EncodePassword (password); + break; + default: + break; + } + if (pass1 == pass2) { + return true; + } + return false; + } + + + // + // EncodePassword + // Encrypts, Hashes, or leaves the password clear based on the PasswordFormat. + // + + private string EncodePassword (string password) + { + string encodedPassword = password; + + switch (PasswordFormat) { + case MembershipPasswordFormat.Clear: + break; + case MembershipPasswordFormat.Encrypted: + encodedPassword = + Convert.ToBase64String (EncryptPassword (Encoding.Unicode.GetBytes (password))); + break; + case MembershipPasswordFormat.Hashed: + HMACSHA1 hash = new HMACSHA1 (); + hash.Key = HexToByte (machineKey.ValidationKey); + encodedPassword = + Convert.ToBase64String (hash.ComputeHash (Encoding.Unicode.GetBytes (password))); + break; + default: + throw new ProviderException ("Unsupported password format."); + } + + return encodedPassword; + } + + + // + // UnEncodePassword + // Decrypts or leaves the password clear based on the PasswordFormat. + // + + private string UnEncodePassword (string encodedPassword) + { + string password = encodedPassword; + + switch (PasswordFormat) { + case MembershipPasswordFormat.Clear: + break; + case MembershipPasswordFormat.Encrypted: + password = + Encoding.Unicode.GetString (DecryptPassword (Convert.FromBase64String (password))); + break; + case MembershipPasswordFormat.Hashed: + throw new ProviderException ("Cannot unencode a hashed password."); + default: + throw new ProviderException ("Unsupported password format."); + } + + return password; + } + + // + // HexToByte + // Converts a hexadecimal string to a byte array. Used to convert encryption + // key values from the configuration. + // + + private byte[] HexToByte (string hexString) + { + byte[] returnBytes = new byte[hexString.Length / 2]; + for (int i = 0; i < returnBytes.Length; i++) + returnBytes [i] = Convert.ToByte (hexString.Substring (i * 2, 2), 16); + return returnBytes; + } + + + // + // MembershipProvider.FindUsersByName + // + + public override MembershipUserCollection FindUsersByName (string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) + { + MembershipUserCollection users = new MembershipUserCollection (); + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT count(*)" + + " FROM Users " + + " WHERE Username LIKE @UsernameSearch AND ApplicationName = @ApplicationName ", conn)) { + totalRecords = (int)cmd.ExecuteScalar (); + } + if (totalRecords > 0) + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT PKID, Username, Email, PasswordQuestion," + + " Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate," + + " LastActivityDate, LastPasswordChangedDate, LastLockedOutDate " + + " FROM Users " + + " WHERE Username LIKE @UsernameSearch AND ApplicationName = @ApplicationName " + + " ORDER BY Username Asc", conn)) { + cmd.Parameters.Add ("@UsernameSearch", NpgsqlDbType.Varchar, 255).Value = usernameToMatch; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = pApplicationName; + conn.Open (); + using (NpgsqlDataReader reader = cmd.ExecuteReader ()) { + int counter = 0; + int startIndex = pageSize * pageIndex; + int endIndex = startIndex + pageSize - 1; + + while (reader.Read()) { + if (counter >= startIndex) { + MembershipUser u = GetUserFromReader (reader); + users.Add (u); + } + if (counter >= endIndex) { + cmd.Cancel (); + } + counter++; + } + reader.Close (); + } + conn.Close (); + } + } + return users; + } + + // + // MembershipProvider.FindUsersByEmail + // + + public override MembershipUserCollection FindUsersByEmail (string emailToMatch, int pageIndex, int pageSize, out int totalRecords) + { + MembershipUserCollection users = new MembershipUserCollection (); + using (NpgsqlConnection conn = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT count(*) " + + " FROM Users " + + " WHERE Email LIKE @EmailSearch AND ApplicationName = @ApplicationName ", conn)) { + totalRecords = (int)cmd.ExecuteScalar (); + } + + using (NpgsqlCommand cmd = new NpgsqlCommand ("SELECT PKID, Username, Email, PasswordQuestion," + + " Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate," + + " LastActivityDate, LastPasswordChangedDate, LastLockedOutDate" + + " FROM Users " + + " WHERE Email LIKE @EmailSearch AND ApplicationName = @ApplicationName " + + " ORDER BY Username Asc", conn)) { + cmd.Parameters.Add ("@EmailSearch", NpgsqlDbType.Varchar, 255).Value = emailToMatch; + cmd.Parameters.Add ("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = ApplicationName; + conn.Open (); + using (NpgsqlDataReader reader = cmd.ExecuteReader ()) { + int counter = 0; + int startIndex = pageSize * pageIndex; + int endIndex = startIndex + pageSize - 1; + + while (reader.Read()) { + if (counter >= startIndex) { + MembershipUser u = GetUserFromReader (reader); + users.Add (u); + } + if (counter >= endIndex) { + cmd.Cancel (); + } + counter++; + } + reader.Close (); + } + conn.Close (); + } + } + return users; + } + + } +} diff --git a/NpgsqlMRPProviders/NpgsqlProfileProvider.cs b/NpgsqlMRPProviders/NpgsqlProfileProvider.cs new file mode 100644 index 00000000..44e362cc --- /dev/null +++ b/NpgsqlMRPProviders/NpgsqlProfileProvider.cs @@ -0,0 +1,237 @@ +using System; +using System.Configuration; +using System.Web.Profile; +using Npgsql; + +namespace Npgsql.Web +{ + public class NpgsqlProfileProvider: ProfileProvider + { + private string connectionString; + private string applicationName; + + public NpgsqlProfileProvider () + { + } + + public override void Initialize (string iname, System.Collections.Specialized.NameValueCollection config) + { + // get the + // - application name + // - connection string name + // - the connection string from its name + string cnxName = config ["connectionStringName"]; + connectionString = ConfigurationManager.ConnectionStrings [cnxName].ConnectionString; + config.Remove ("connectionStringName"); + applicationName = config ["applicationName"]; + config.Remove ("applicationName"); + base.Initialize (iname, config); + } + + #region implemented abstract members of System.Web.Profile.ProfileProvider + + public override int DeleteInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) + { + throw new System.NotImplementedException (); + } + + public override int DeleteProfiles (string[] usernames) + { + throw new System.NotImplementedException (); + } + + public override int DeleteProfiles (ProfileInfoCollection profiles) + { + throw new System.NotImplementedException (); + } + + public override ProfileInfoCollection FindInactiveProfilesByUserName (ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) + { + throw new System.NotImplementedException (); + } + + public override ProfileInfoCollection FindProfilesByUserName (ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) + { + if (pageIndex < 0) + throw new ArgumentException ("pageIndex"); + if (pageSize < 1) + throw new ArgumentException ("pageSize"); + + long lowerBound = (long)pageIndex * pageSize; + long upperBound = lowerBound + pageSize - 1; + if (upperBound > Int32.MaxValue) + throw new ArgumentException ("lowerBound + pageSize*pageIndex -1 > Int32.MaxValue"); + ProfileInfoCollection c = new ProfileInfoCollection (); + totalRecords = 0; + + using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) { + using (NpgsqlCommand cmd = cnx.CreateCommand ()) { + cmd.CommandText = "select username, uniqueid, lastactivitydate, lastupdateddate, isanonymous from profiles where username like @username and applicationname = @appname"; + cmd.Parameters.Add ("@username", usernameToMatch); + cmd.Parameters.Add ("@appname", applicationName); + cnx.Open (); + using (NpgsqlDataReader r = cmd.ExecuteReader ()) { + if (r.HasRows) { + while (r.Read ()) { + if (totalRecords >= lowerBound && totalRecords <= upperBound) { + + object o = r.GetValue (r.GetOrdinal ("isanonymous")); + bool isanon = o is DBNull ? true : (bool) o; + o = r.GetValue (r.GetOrdinal ("lastactivitydate")); + DateTime lact = o is DBNull ? new DateTime() : (DateTime) o; + o = r.GetValue (r.GetOrdinal ("lastupdateddate")); + DateTime lupd = o is DBNull ? new DateTime() : (DateTime) o; + ProfileInfo pi = + new ProfileInfo ( + r.GetString (r.GetOrdinal ("username")), + isanon, + lact, + lupd, + 0); + c.Add (pi); + totalRecords++; + } + } + } + } + } + + } + return c; + } + + public override ProfileInfoCollection GetAllInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) + { + throw new System.NotImplementedException (); + } + + public override ProfileInfoCollection GetAllProfiles (ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords) + { + throw new System.NotImplementedException (); + } + + public override int GetNumberOfInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) + { + throw new System.NotImplementedException (); + } + + #endregion + + #region implemented abstract members of System.Configuration.SettingsProvider + + public override SettingsPropertyValueCollection GetPropertyValues (SettingsContext context, SettingsPropertyCollection collection) + { + SettingsPropertyValueCollection c = new SettingsPropertyValueCollection (); + if (collection == null || collection.Count < 1 || context == null) + return c; + string username = (string)context ["UserName"]; + if (String.IsNullOrEmpty (username)) + return c; + using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) + using (NpgsqlCommand cmd = cnx.CreateCommand ()) { + cmd.CommandText = "SELECT * from profiledata,profiles where " + + "profiledata.uniqueid = profiles.uniqueid " + + "and profiles.username = @username " + + "and profiles.applicationname = @appname"; + cmd.Parameters.Add ("@username", username); + cmd.Parameters.Add ("@appname", applicationName); + cnx.Open (); + using (NpgsqlDataReader r = cmd.ExecuteReader ( + System.Data.CommandBehavior.CloseConnection | System.Data.CommandBehavior.SingleRow)) { + if (r.Read ()) { + foreach (SettingsProperty p in collection) { + SettingsPropertyValue v = new SettingsPropertyValue (p); + int o = r.GetOrdinal (p.Name.ToLower ()); + v.PropertyValue = r.GetValue (o); + c.Add (v); + } + } else { + foreach (SettingsProperty p in collection) { + SettingsPropertyValue v = new SettingsPropertyValue (p); + v.PropertyValue = null; + c.Add (v); + } + } + } + } + return c; + + } + + public override void SetPropertyValues (SettingsContext context, SettingsPropertyValueCollection collection) + { + // get the unique id of the profile + if (collection == null) + return; + long puid = 0; + string username = (string)context ["UserName"]; + + using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) { + cnx.Open (); + using (NpgsqlCommand cmdpi = cnx.CreateCommand ()) { + cmdpi.CommandText = "select count(uniqueid) " + + "from profiles where username = @username " + + "and applicationname = @appname"; + cmdpi.Parameters.Add ("@username", username); + cmdpi.Parameters.Add ("@appname", applicationName); + + long c = (long)cmdpi.ExecuteScalar (); + if (c == 0) { + cmdpi.CommandText = "insert into profiles (username,applicationname) " + + "values ( @username, @appname ) " + + "returning uniqueid"; + puid = (long)cmdpi.ExecuteScalar (); + // TODO spec: profiledata insertion <=> profile insertion + // => BAD DESIGN + // + using (NpgsqlCommand cmdpdins = cnx.CreateCommand ()) { + cmdpdins.CommandText = "insert into profiledata (uniqueid) values (@puid)"; + cmdpdins.Parameters.Add ("@puid", puid); + cmdpdins.ExecuteNonQuery (); + } + } else { + cmdpi.CommandText = "select uniqueid from profiles where username = @username " + + "and applicationname = @appname"; + puid = (long)cmdpi.ExecuteScalar (); + } + } + + + foreach (SettingsPropertyValue s in collection) { + if (s.UsingDefaultValue) { + //TODO Drop the property in the profile + } else { + // update the property value + // TODO update to null values (included to avoid Not Implemented columns in profiledata + if (s.PropertyValue != null) { + using (NpgsqlCommand cmd = cnx.CreateCommand ()) { + cmd.CommandText = string.Format ( + "update profiledata " + + "set {0} = @val " + + "where uniqueid = @puid ", + s.Name + ); + cmd.Parameters.Add ("@puid", puid); + cmd.Parameters.Add ("@val", s.PropertyValue); + cmd.ExecuteNonQuery (); + } + } + } + } + } + } + + public override string ApplicationName { + get { + return applicationName; + } + set { + applicationName = value; + } + } + + #endregion + + } +} + diff --git a/NpgsqlMRPProviders/NpgsqlRoleProvider.cs b/NpgsqlMRPProviders/NpgsqlRoleProvider.cs new file mode 100644 index 00000000..c583d8ea --- /dev/null +++ b/NpgsqlMRPProviders/NpgsqlRoleProvider.cs @@ -0,0 +1,364 @@ +using System; +using System.Web.Security; +using System.Configuration.Provider; +using System.Configuration; +using Npgsql; +using System.Collections.Generic; + +/* + * +CREATE TABLE roles +( + rolename character varying(255) NOT NULL, + applicationname character varying(255) NOT NULL, + comment character varying(255) NOT NULL, + CONSTRAINT roles_pkey PRIMARY KEY (rolename , applicationname ) +) +WITH ( + OIDS=FALSE +); + +CREATE TABLE usersroles +( + applicationname character varying(255) NOT NULL, + rolename character varying(255) NOT NULL, + username character varying(255) NOT NULL, + CONSTRAINT attrroles_pkey PRIMARY KEY (applicationname , rolename , username ), + CONSTRAINT usersroles_fk_role FOREIGN KEY (applicationname, rolename) + REFERENCES roles (applicationname, rolename) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT usersroles_fk_user FOREIGN KEY (applicationname, username) + REFERENCES users (applicationname, username) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE +) +WITH ( + OIDS=FALSE +); + + */ +using System.Linq; + + +namespace Npgsql.Web +{ + public class NpgsqlRoleProvider: RoleProvider + { + protected string name = "NpgsqlRoleProvider"; + protected string connectionStringName = "pgProvider"; + protected string applicationName = "/"; + protected string connectionString = string.Empty; + + public override void Initialize (string iname, System.Collections.Specialized.NameValueCollection config) + { + try { + + name = iname ?? config ["name"]; + + connectionStringName = config ["connectionStringName"] ?? connectionStringName; + + applicationName = config ["applicationName"] ?? applicationName; + + if (applicationName.Length > 250) + throw new ProviderException ("The maximum length for an application name is 250 characters."); + + var cs = ConfigurationManager.ConnectionStrings [connectionStringName]; + if (cs == null || string.IsNullOrEmpty (cs.ConnectionString)) { + throw new ProviderException ( + string.Format ("The role provider connection string, '{0}', is not defined.", connectionStringName)); + } + + connectionString = ConfigurationManager.ConnectionStrings [connectionStringName].ConnectionString; + if (string.IsNullOrEmpty (connectionString)) + throw new ConfigurationErrorsException ( + string.Format ( + "The connection string for the given name ({0})" + + "must be specified in the " + + "configuration bloc. Aborting.", connectionStringName) + ); + + } catch (Exception ex) { + var message = "Error initializing the role configuration settings"; + throw new ProviderException (message, ex); + } + } + + public override void AddUsersToRoles (string[] usernames, string[] roleNames) + { + if (usernames.Any (x => x == null) || roleNames.Any (x => x == null)) { + throw new ArgumentNullException (); + } + if (usernames.Any (x => x.Trim () == string.Empty) || (roleNames.Any (x => x.Trim () == string.Empty))) { + throw new ArgumentException ("One or more of the supplied usernames or role names are empty."); + } + + + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "insert into usersroles (applicationname, username, rolename) values (@appname,@user,@role)"; + comm.Parameters.Add ("appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + NpgsqlParameter pu = comm.Parameters.Add ("user", NpgsqlTypes.NpgsqlDbType.Varchar, 250); + NpgsqlParameter pr = comm.Parameters.Add ("role", NpgsqlTypes.NpgsqlDbType.Varchar, 250); + foreach (string u in usernames) { + pu.Value = u; + foreach (string r in roleNames) { + pr.Value = r; + comm.ExecuteNonQuery (); + } + } + } + + } + + } + + public override string ApplicationName { + get { + return applicationName; + } + set { + applicationName = value; + } + } + + public override void CreateRole (string roleName) + { + if (roleName == null) + throw new ArgumentNullException (); + if (roleName.Trim () == string.Empty) + throw new ArgumentException ("A role name cannot be empty."); + if (roleName.Contains (",")) + throw new ArgumentException ("A role name cannot contain commas. Blame Microsoft for that rule!"); + if (roleName.Length > 250) + throw new ArgumentException ("The maximum length for a Role name is 250 characters."); + + + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "insert into roles (rolename, applicationname, comment) values (@rolename, @appname, @comment)"; + comm.Parameters.Add ("@rolename", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = roleName; + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + comm.Parameters.Add ("@comment", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = roleName; + comm.ExecuteNonQuery (); + } + } + + } + + public override bool DeleteRole (string roleName, bool throwOnPopulatedRole) + { + if (roleName == null) + throw new ArgumentNullException (); + if (roleName.Trim () == string.Empty) + throw new ArgumentException ("The specified role name cannot be empty."); + if (throwOnPopulatedRole) + if (FindUsersInRole (roleName, "").Count () > 0) + throw new ProviderException ( + string.Format ("The role {0} is populated, we cannot delete it.", roleName)); + + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "delete from roles where rolename = @rolename and applicationname = @appname"; + comm.Parameters.Add ("@rolename", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = roleName; + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + comm.Parameters.Add ("@comment", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = roleName; + comm.ExecuteNonQuery (); + } + } + return true; + } + + public override string[] FindUsersInRole (string roleName, string usernameToMatch) + { + return GetUsersInRole (roleName, usernameToMatch); + } + + protected string[] GetUsersInRole (string rolename, string usernameToMatch) + { + if (rolename == null) + throw new ArgumentNullException (); + if (rolename == string.Empty) + throw new ProviderException ("Cannot look for blank role names."); + usernameToMatch = usernameToMatch ?? string.Empty; + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "select username from usersroles where applicationname = @appname " + + "and rolename = @rolename and username like @username"; + comm.Parameters.Add ("@rolename", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = rolename; + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + comm.Parameters.Add ("@username", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = usernameToMatch; + using (var reader = comm.ExecuteReader()) { + var r = new List (); + var usernameColumn = reader.GetOrdinal ("username"); + while (reader.Read()) { + r.Add (reader.GetString (usernameColumn)); + } + return r.ToArray (); + } + } + } + } + + public override string[] GetAllRoles () + { + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "select rolename from roles where applicationname = @appname"; + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + using (var reader = comm.ExecuteReader()) { + var r = new List (); + var rolenameColumn = reader.GetOrdinal ("rolename"); + while (reader.Read()) { + r.Add (reader.GetString (rolenameColumn)); + } + return r.ToArray (); + } + } + } + } + + public override string[] GetRolesForUser (string username) + { + if (username == null) + throw new ArgumentNullException (); + if (username.Trim () == string.Empty) + throw new ArgumentException ("The specified username cannot be blank."); + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "select rolename from usersroles where applicationname = @appname and username = @username"; + comm.Parameters.Add ("@username", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = username; + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + using (var reader = comm.ExecuteReader()) { + var r = new List (); + var rolenameColumn = reader.GetOrdinal ("rolename"); + while (reader.Read()) { + r.Add (reader.GetString (rolenameColumn)); + } + return r.ToArray (); + } + } + } + } + + public override string[] GetUsersInRole (string roleName) + { + if (string.IsNullOrEmpty (roleName)) + throw new ArgumentException ("The specified role name cannot be blank or null"); + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + // + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "select username from usersroles where applicationname = @appname " + + "and rolename = @rolename"; + comm.Parameters.Add ("@rolename", NpgsqlTypes.NpgsqlDbType.Varchar, 255).Value = roleName; + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 255).Value = applicationName; + using (var reader = comm.ExecuteReader()) { + var r = new List (); + var usernameColumn = reader.GetOrdinal ("username"); + while (reader.Read()) { + r.Add (reader.GetString (usernameColumn)); + } + return r.ToArray (); + } + } + } + } + + public override bool IsUserInRole (string username, string roleName) + { + if (username == null || roleName == null) + throw new ArgumentNullException (); + if (username.Trim () == string.Empty) + throw new ArgumentException ("The specified username cannot be blank."); + if (roleName.Trim () == string.Empty) + throw new ArgumentException ("The specified role name cannot be blank."); + + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + // + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "select count(*)>0 from usersroles where applicationname = @appname " + + "and username = @username and rolename = @rolename"; + comm.Parameters.Add ("@username", username); + comm.Parameters.Add ("@rolename", roleName); + comm.Parameters.Add ("@appname", applicationName); + var retval = (bool)comm.ExecuteScalar (); + return retval; + } + } + + } + + public override void RemoveUsersFromRoles (string[] usernames, string[] roleNames) + { + if (usernames.Any (x => x == null) || roleNames.Any (x => x == null)) { + throw new ArgumentNullException (); + } + if (usernames.Any (x => x.Trim () == string.Empty) || (roleNames.Any (x => x.Trim () == string.Empty))) { + throw new ArgumentException ("One or more of the supplied usernames or role names are empty."); + } + + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = conn.CreateCommand()) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "delete from usersroles where applicationname = @appname and " + + "username = @username and rolename = @rolename"; + NpgsqlParameter pu = comm.Parameters.Add ("@username", NpgsqlTypes.NpgsqlDbType.Varchar, 250); + NpgsqlParameter pr = comm.Parameters.Add ("@rolename", NpgsqlTypes.NpgsqlDbType.Varchar, 250); + comm.Parameters.Add ("@appname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + foreach (string rolename in roleNames) { + pr.Value = rolename; + foreach (string username in usernames) { + pu.Value = username; + comm.ExecuteNonQuery (); + } + } + } + } + + } + + public override bool RoleExists (string roleName) + { + using (var conn = new NpgsqlConnection(connectionString)) { + conn.Open (); + using (var comm = new NpgsqlCommand("role_exists", conn)) { + comm.CommandType = System.Data.CommandType.Text; + comm.CommandText = "select Count(*)>0 from roles where applicationname = @applicationname and rolename = @rolename"; + comm.Parameters.Add ("@rolename", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = roleName; + comm.Parameters.Add ("@applicationname", NpgsqlTypes.NpgsqlDbType.Varchar, 250).Value = applicationName; + var retval = (bool)comm.ExecuteScalar (); + return retval; + } + } + } + + public override string Name { + get { + return name; + } + } + + public override string Description { + get { + return "PostgreSQL ASP.Net Role Provider class"; + } + } + } +} + diff --git a/NpgsqlMRPProviders/Sql/ProfileData.sql b/NpgsqlMRPProviders/Sql/ProfileData.sql new file mode 100644 index 00000000..76d63571 --- /dev/null +++ b/NpgsqlMRPProviders/Sql/ProfileData.sql @@ -0,0 +1,28 @@ +-- Table: profiledata + +-- DROP TABLE profiledata; + +CREATE TABLE profiledata +( + uniqueid integer, + zipcode character varying(10), + cityandstate character varying(255), + avatar bytea, + CONSTRAINT fkprofiles2 FOREIGN KEY (uniqueid) + REFERENCES profiles (uniqueid) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE +) +WITH ( + OIDS=FALSE +); + +-- Index: fki_fkprofiles2 + +-- DROP INDEX fki_fkprofiles2; + +CREATE INDEX fki_fkprofiles2 + ON profiledata + USING btree + (uniqueid ); + + diff --git a/NpgsqlMRPProviders/Sql/RolesTable.sql b/NpgsqlMRPProviders/Sql/RolesTable.sql new file mode 100644 index 00000000..71e9fc0f --- /dev/null +++ b/NpgsqlMRPProviders/Sql/RolesTable.sql @@ -0,0 +1,18 @@ +-- Table: roles + +-- DROP TABLE roles; + +CREATE TABLE roles +( + rolename character varying(255) NOT NULL, + applicationname character varying(255) NOT NULL, + comment character varying(255) NOT NULL, + CONSTRAINT roles_pkey PRIMARY KEY (rolename , applicationname ) +) +WITH ( + OIDS=FALSE +); + +COMMENT ON TABLE roles + IS 'Web application roles'; + diff --git a/NpgsqlMRPProviders/Sql/StockSymbols.sql b/NpgsqlMRPProviders/Sql/StockSymbols.sql new file mode 100644 index 00000000..53a88c2f --- /dev/null +++ b/NpgsqlMRPProviders/Sql/StockSymbols.sql @@ -0,0 +1,16 @@ + +-- Table: stocksymbols + +-- DROP TABLE stocksymbols; + +CREATE TABLE stocksymbols +( + uniqueid integer, + stocksymbol character varying(10), + CONSTRAINT fkprofiles1 FOREIGN KEY (uniqueid) + REFERENCES profiles (uniqueid) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION +) +WITH ( + OIDS=FALSE +); diff --git a/NpgsqlMRPProviders/Sql/UserRoleTable.sql b/NpgsqlMRPProviders/Sql/UserRoleTable.sql new file mode 100644 index 00000000..639ee34e --- /dev/null +++ b/NpgsqlMRPProviders/Sql/UserRoleTable.sql @@ -0,0 +1,21 @@ + +-- Table: usersroles + +-- DROP TABLE usersroles; + +CREATE TABLE usersroles +( + applicationname character varying(255) NOT NULL, + rolename character varying(255) NOT NULL, + username character varying(255) NOT NULL, + CONSTRAINT attrroles_pkey PRIMARY KEY (applicationname , rolename , username ), + CONSTRAINT usersroles_fk_role FOREIGN KEY (applicationname, rolename) + REFERENCES roles (applicationname, rolename) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT usersroles_fk_user FOREIGN KEY (applicationname, username) + REFERENCES users (applicationname, username) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE +) +WITH ( + OIDS=FALSE +); diff --git a/NpgsqlMRPProviders/Sql/UsersTable.sql b/NpgsqlMRPProviders/Sql/UsersTable.sql new file mode 100644 index 00000000..813142da --- /dev/null +++ b/NpgsqlMRPProviders/Sql/UsersTable.sql @@ -0,0 +1,19 @@ +-- Table: profiles + +-- DROP TABLE profiles; + +CREATE TABLE profiles +( + uniqueid bigserial NOT NULL, + username character varying(255) NOT NULL, + applicationname character varying(255) NOT NULL, + isanonymous boolean, + lastactivitydate timestamp with time zone, + lastupdateddate timestamp with time zone, + CONSTRAINT profiles_pkey PRIMARY KEY (uniqueid ), + CONSTRAINT pkprofiles UNIQUE (username , applicationname ) +) +WITH ( + OIDS=FALSE +); + diff --git a/SalesCatalog/AssemblyInfo.cs b/SalesCatalog/AssemblyInfo.cs new file mode 100644 index 00000000..8bc3c1de --- /dev/null +++ b/SalesCatalog/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("SalesCatalog")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("paul")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/SalesCatalog/CatalogHelper.cs b/SalesCatalog/CatalogHelper.cs new file mode 100644 index 00000000..b6a859f0 --- /dev/null +++ b/SalesCatalog/CatalogHelper.cs @@ -0,0 +1,45 @@ +using System; +using System.Configuration; +using System.Reflection; +using System.Collections.Specialized; +using SalesCatalog.Configuration; + +namespace SalesCatalog +{ + /// + /// Catalog helper. + /// Used by the catalog manager to get the catalog provider from the configuration. + /// + public static class CatalogHelper + { + public static CatalogProvider GetProvider () + { + CatalogProvidersConfigurationSection config = ConfigurationManager.GetSection ("system.web/catalog") as CatalogProvidersConfigurationSection; + if (config == null) + throw new ConfigurationErrorsException("The configuration bloc for the catalog provider was not found"); + CatalogProviderConfigurationElement celt = + config.Providers.GetElement (config.DefaultProvider); + if (celt == null) + throw new ConfigurationErrorsException("The default catalog provider was not found"); + Type catprtype = Type.GetType (celt.Type); + if (catprtype == null) + throw new Exception ( + string.Format("The catalog provider type ({0}) could not be found",celt.Type)); + ConstructorInfo ci = catprtype.GetConstructor (Type.EmptyTypes); + if (ci==null) + throw new Exception ( + string.Format("The catalog provider type ({0}) doesn't contain public constructor with empty parameter list",celt.Type)); + + CatalogProvider cp = ci.Invoke (Type.EmptyTypes) as CatalogProvider; + NameValueCollection c = new NameValueCollection (); + c.Add ("name", celt.Name); + c.Add ("type", celt.Type); + c.Add ("connection", celt.Connection); + c.Add ("description", celt.Description); + c.Add ("applicationName", celt.ApplicationName); + cp.Initialize (celt.Name, c); + return cp; + } + } +} + diff --git a/SalesCatalog/CatalogManager.cs b/SalesCatalog/CatalogManager.cs new file mode 100644 index 00000000..d1e77809 --- /dev/null +++ b/SalesCatalog/CatalogManager.cs @@ -0,0 +1,19 @@ +using System; +using SalesCatalog.Model; + +namespace SalesCatalog +{ + /// + /// Catalog manager. + /// Use this class to retreive the catalog or its elements + /// + public static class CatalogManager + { + public static Catalog GetCatalog () + { + CatalogProvider p = CatalogHelper.GetProvider (); + return p.GetCatalog (); + } + } +} + diff --git a/SalesCatalog/CatalogProvider.cs b/SalesCatalog/CatalogProvider.cs new file mode 100644 index 00000000..c7fa1e32 --- /dev/null +++ b/SalesCatalog/CatalogProvider.cs @@ -0,0 +1,16 @@ +using System; +using System.Configuration.Provider; +using SalesCatalog.Model; + +namespace SalesCatalog +{ + /// + /// Catalog provider.
+ /// Abstract class, inherited to implement a catalog provider. + ///
+ public abstract class CatalogProvider: ProviderBase + { + public abstract Catalog GetCatalog (); + } +} + diff --git a/SalesCatalog/Configuration/CatalogProviderConfigurationElement.cs b/SalesCatalog/Configuration/CatalogProviderConfigurationElement.cs new file mode 100644 index 00000000..60488a35 --- /dev/null +++ b/SalesCatalog/Configuration/CatalogProviderConfigurationElement.cs @@ -0,0 +1,39 @@ +using System; +using System.Configuration; + +namespace SalesCatalog.Configuration +{ + + public class CatalogProviderConfigurationElement : ConfigurationElement + { + [ConfigurationProperty("name", IsRequired = true, IsKey=true)] + public string Name { + get { return (string)this ["name"]; } + set { this ["name"] = value; } + } + + [ConfigurationProperty("type", IsRequired = true)] + public string Type { + get { return (string)this ["type"]; } + set { this ["type"] = value; } + } + + [ConfigurationProperty("connection")] + public string Connection { + get { return (string)this ["connection"]; } + set { this ["connection"] = value; } + } + + [ConfigurationProperty("description")] + public string Description { + get { return (string)this ["description"]; } + set { this ["description"] = value; } + } + + [ConfigurationProperty("applicationName")] + public string ApplicationName { + get { return (string)this ["applicationName"]; } + set { this ["applicationName"] = value; } + } + } +} diff --git a/SalesCatalog/Configuration/CatalogProvidersConfigurationCollection.cs b/SalesCatalog/Configuration/CatalogProvidersConfigurationCollection.cs new file mode 100644 index 00000000..cf1491a2 --- /dev/null +++ b/SalesCatalog/Configuration/CatalogProvidersConfigurationCollection.cs @@ -0,0 +1,26 @@ +using System; +using System.Configuration; +using System.ComponentModel; + +namespace SalesCatalog.Configuration +{ + public class CatalogProvidersConfigurationCollection : ConfigurationElementCollection + { + protected override ConfigurationElement CreateNewElement () + { + return new CatalogProviderConfigurationElement(); + } + + protected override object GetElementKey (ConfigurationElement element) + { + return ((CatalogProviderConfigurationElement) element).Name; + } + + public CatalogProviderConfigurationElement GetElement (string name) + { + return this.BaseGet(name) as CatalogProviderConfigurationElement; + } + } + +} + diff --git a/SalesCatalog/Configuration/CatalogProvidersConfigurationSection.cs b/SalesCatalog/Configuration/CatalogProvidersConfigurationSection.cs new file mode 100644 index 00000000..b6f945c9 --- /dev/null +++ b/SalesCatalog/Configuration/CatalogProvidersConfigurationSection.cs @@ -0,0 +1,26 @@ +using System; +using System.Configuration; +using System.ComponentModel; + +namespace SalesCatalog.Configuration +{ + public class CatalogProvidersConfigurationSection : ConfigurationSection + { + [ConfigurationProperty("defaultProvider")] + public string DefaultProvider { + get { return (string)base ["defaultProvider"]; } + set { base ["defaultProvider"] = value; } + } + + [ConfigurationProperty("providers")] + [ConfigurationCollection(typeof(CatalogProvidersConfigurationCollection), + AddItemName = "add", + ClearItemsName = "clear", + RemoveItemName = "remove")] + public CatalogProvidersConfigurationCollection Providers{ + get { return (CatalogProvidersConfigurationCollection) base ["providers"]; } + set { base ["providers"] = value; } + } + } + +} diff --git a/SalesCatalog/Model/Brand.cs b/SalesCatalog/Model/Brand.cs new file mode 100644 index 00000000..0c948542 --- /dev/null +++ b/SalesCatalog/Model/Brand.cs @@ -0,0 +1,37 @@ +using System; +using System.Xml.Serialization; +using System.ComponentModel.DataAnnotations; + +namespace SalesCatalog.Model +{ + public class Brand + { + public Brand () + { + } + + [Required] + public string Name { get; set; } + + public string Slogan { get; set; } + + public ProductImage Logo { get; set; } + + public ProductCategory[] Categories { get; set; } + /// + /// Gets or sets the default form. + /// + /// The default form. + public SaleForm DefaultForm { get; set; } + + public ProductCategory GetProductCategory(string reference) + { + return Array.Find(Categories, c => c.Reference == reference); + } + public ProductCategory GetProductCategoryByName(string catName) + { + return Array.Find(Categories, c => c.Name == catName); + } + } +} + diff --git a/SalesCatalog/Model/Catalog.cs b/SalesCatalog/Model/Catalog.cs new file mode 100644 index 00000000..93dad93a --- /dev/null +++ b/SalesCatalog/Model/Catalog.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; + +namespace SalesCatalog.Model +{ + /// + /// Catalog. + /// + public class Catalog { + /// + /// Gets or sets the brands. + /// + /// The brands. + public Brand[] Brands { get; set; } + + public Brand GetBrand(string brandName) + { + return Array.Find(Brands, b => b.Name == brandName); + } + + public Brand AddBrand(string brandName,string slogan=null, ProductImage logo=null) + { + Brand[] oldbrs = (Brand[]) Brands.Clone (); + int oldl = Brands.Length; + Array.Resize(ref oldbrs,oldl+1); + Brand b = new Brand (); + b.Name=brandName; + b.Slogan = slogan; + b.Logo = logo; + oldbrs [oldl] = b; + Brands=oldbrs; + return b; + } + + public bool RemoveBrand(string brandName) + { + Brand b = this.GetBrand (brandName); + if (b == null) + return false; + //assert(Brands.Length>0); + List nb = new List (Brands); + nb.Remove (b); + Brands = nb.ToArray (); + return true; + } + + public DateTime StartDate { get; set; } + + public DateTime EndDate { get; set; } + + } + +} diff --git a/SalesCatalog/Model/CheckBox.cs b/SalesCatalog/Model/CheckBox.cs new file mode 100644 index 00000000..b1e37c20 --- /dev/null +++ b/SalesCatalog/Model/CheckBox.cs @@ -0,0 +1,18 @@ +using System; + +namespace SalesCatalog.Model +{ + public class CheckBox : FormInput + { + public CheckBox () + { + } + public bool Value { get; set; } + + public override string ToHtml () + { + return string.Format ("", Id,Name,Value?"checked":""); + } + } +} + diff --git a/SalesCatalog/Model/Currency.cs b/SalesCatalog/Model/Currency.cs new file mode 100644 index 00000000..0700448c --- /dev/null +++ b/SalesCatalog/Model/Currency.cs @@ -0,0 +1,9 @@ +using System; + +namespace SalesCatalog.Model +{ + public abstract class Currency: Unit + { + } +} + diff --git a/SalesCatalog/Model/Euro.cs b/SalesCatalog/Model/Euro.cs new file mode 100644 index 00000000..72e3f576 --- /dev/null +++ b/SalesCatalog/Model/Euro.cs @@ -0,0 +1,34 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Euro : Currency + { + public Euro () + { + } + + public override string Name { + get { + return "Euro"; + } + } + + public override string Description { + get { + return "European currency"; + } + } + + public override bool MayConvertTo (Unit other) + { + return other.GetType().IsSubclassOf(typeof (Currency)); + } + + public override object ConvertTo (Unit dest, object value) + { + throw new NotImplementedException(); + } + } +} + diff --git a/SalesCatalog/Model/FilesInput.cs b/SalesCatalog/Model/FilesInput.cs new file mode 100644 index 00000000..8fd64376 --- /dev/null +++ b/SalesCatalog/Model/FilesInput.cs @@ -0,0 +1,18 @@ +using System; + +namespace SalesCatalog.Model +{ + public class FilesInput : FormInput + { + + public FilesInput () + { + } + + public override string ToHtml () + { + return string.Format ("", Id); + } + } +} + diff --git a/SalesCatalog/Model/FormElement.cs b/SalesCatalog/Model/FormElement.cs new file mode 100644 index 00000000..283c0312 --- /dev/null +++ b/SalesCatalog/Model/FormElement.cs @@ -0,0 +1,10 @@ +using System; + +namespace SalesCatalog.Model +{ + public abstract class FormElement + { + public abstract string ToHtml (); + } +} + diff --git a/SalesCatalog/Model/FormInput.cs b/SalesCatalog/Model/FormInput.cs new file mode 100644 index 00000000..63a8e1d9 --- /dev/null +++ b/SalesCatalog/Model/FormInput.cs @@ -0,0 +1,19 @@ +using System; + +namespace SalesCatalog.Model +{ + public abstract class FormInput: FormElement + { + /// + /// Gets or sets the identifier, unique in its Form. + /// + /// + /// The identifier. + /// + + public string Id { get; set; } + private string name=null; + public string Name { get { return name == null ? Id : name; } set { name = value; } } + } +} + diff --git a/SalesCatalog/Model/Label.cs b/SalesCatalog/Model/Label.cs new file mode 100644 index 00000000..6b3c9803 --- /dev/null +++ b/SalesCatalog/Model/Label.cs @@ -0,0 +1,18 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Label:FormElement + { + public Label () + { + } + string Text { get; set; } + string For { get; set ; } + public override string ToHtml () + { + return string.Format ("", For, Text); + } + } +} + diff --git a/SalesCatalog/Model/Link.cs b/SalesCatalog/Model/Link.cs new file mode 100644 index 00000000..728c824c --- /dev/null +++ b/SalesCatalog/Model/Link.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace SalesCatalog.Model +{ + public class Link:Label + { + public Link () + { + } + [Required] + public string Ref { get; set; } + } +} + diff --git a/SalesCatalog/Model/Note.cs b/SalesCatalog/Model/Note.cs new file mode 100644 index 00000000..add594c4 --- /dev/null +++ b/SalesCatalog/Model/Note.cs @@ -0,0 +1,13 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Note:Text + { + public override string ToHtml () + { + return string.Format("{0}",Val); + } + } +} + diff --git a/SalesCatalog/Model/Option.cs b/SalesCatalog/Model/Option.cs new file mode 100644 index 00000000..daeea5a3 --- /dev/null +++ b/SalesCatalog/Model/Option.cs @@ -0,0 +1,19 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Option : FormElement + { + public Option () + { + } + public string Value { get; set; } + public string Text { get; set; } + + public override string ToHtml () + { + return string.Format ("\n",Value,Text); + } + } +} + diff --git a/SalesCatalog/Model/Period.cs b/SalesCatalog/Model/Period.cs new file mode 100644 index 00000000..b4e30b31 --- /dev/null +++ b/SalesCatalog/Model/Period.cs @@ -0,0 +1,15 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Period + { + public Period () + { + } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + + } +} + diff --git a/SalesCatalog/Model/PhysicalProduct.cs b/SalesCatalog/Model/PhysicalProduct.cs new file mode 100644 index 00000000..c90c14ee --- /dev/null +++ b/SalesCatalog/Model/PhysicalProduct.cs @@ -0,0 +1,27 @@ +using System; + +namespace SalesCatalog.Model +{ + public class PhysicalProduct : Product + { + public PhysicalProduct () + { + } + public Price UnitaryPrice { get; set; } + #region implemented abstract members of SalesCatalog.Model.Product + public override string[] GetSalesConditions () + { + return new string [] { string.Format( + "Prix unitaire : {0} {1}", + UnitaryPrice.Quantity.ToString(), + UnitaryPrice.Unit.Name) }; + } + #endregion + + public override string ToString () + { + return string.Format ("[PhysicalProduct: UnitaryPrice={0}]", UnitaryPrice); + } + } +} + diff --git a/SalesCatalog/Model/Price.cs b/SalesCatalog/Model/Price.cs new file mode 100644 index 00000000..dee40da1 --- /dev/null +++ b/SalesCatalog/Model/Price.cs @@ -0,0 +1,36 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Price: Scalar + { + public Price () + { + } + + decimal quantity; + + #region implemented abstract members of SalesCatalog.Value + public override object Quantity { + get { + return quantity; + } + set { + quantity = (decimal) value; + } + } + + Currency curr; + public override SalesCatalog.Model.Unit Unit { + get { + return curr; + } + set { + curr = (Currency)value; + } + } + #endregion + + } +} + diff --git a/SalesCatalog/Model/Product.cs b/SalesCatalog/Model/Product.cs new file mode 100644 index 00000000..10f1b356 --- /dev/null +++ b/SalesCatalog/Model/Product.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace SalesCatalog.Model +{ + /// + /// Product. + /// Crucial object in the catalog, + /// being at each origin of form display + /// its properties may be used to fill some form input values or other form element. + /// in text values, within {} ex: {Name} : {Price} ({stockStatus}) ($description) . + /// + public abstract class Product + { + /// + /// Gets or sets the product name. + /// + /// The name. + [Required] + [StringLength(1024)] + public string Name { get; set; } + /// + /// Gets or sets the product description. + /// + /// The description. + public string Description { get; set; } + public ProductImage[] Images { get; set; } + public SaleForm CommandForm { get; set; } + [Required] + [StringLength(255)] + public string Reference { get; set; } + public Period CommandValidityDates { get; set; } + public abstract string[] GetSalesConditions(); + + } +} + diff --git a/SalesCatalog/Model/ProductCategory.cs b/SalesCatalog/Model/ProductCategory.cs new file mode 100644 index 00000000..be88b5b9 --- /dev/null +++ b/SalesCatalog/Model/ProductCategory.cs @@ -0,0 +1,23 @@ +using System; + +namespace SalesCatalog.Model +{ + public class ProductCategory + { + public ProductCategory () + { + } + public string Name { get; set; } + public string Reference { get; set; } + public Product[] Products { get; set; } + public Product GetProductByName (string productName) + { + return Array.Find (Products, p => p.Name == productName); + } + public Product GetProduct (string reference) + { + return Array.Find (Products, p => p.Reference == reference); + } + } +} + diff --git a/SalesCatalog/Model/ProductImage.cs b/SalesCatalog/Model/ProductImage.cs new file mode 100644 index 00000000..83bc5822 --- /dev/null +++ b/SalesCatalog/Model/ProductImage.cs @@ -0,0 +1,23 @@ +using System; + +namespace SalesCatalog.Model +{ + public class ProductImage: FormElement + { + #region implemented abstract members of FormElement + + public override string ToHtml () + { + return string.Format ("\"\"/", Src, Alt); + } + + #endregion + + public ProductImage () + { + } + public string Src { get; set; } + public string Alt { get; set; } + } +} + diff --git a/SalesCatalog/Model/RadioButton.cs b/SalesCatalog/Model/RadioButton.cs new file mode 100644 index 00000000..2cb3917d --- /dev/null +++ b/SalesCatalog/Model/RadioButton.cs @@ -0,0 +1,17 @@ +using System; + +namespace SalesCatalog.Model +{ + public class RadioButton:FormInput + { + public RadioButton () + { + } + public string Choice { get; set; } + public override string ToHtml () + { + return string.Format ("", Id,Name,Choice); + } + } +} + diff --git a/SalesCatalog/Model/SaleForm.cs b/SalesCatalog/Model/SaleForm.cs new file mode 100644 index 00000000..436b1032 --- /dev/null +++ b/SalesCatalog/Model/SaleForm.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace SalesCatalog.Model +{ + public class SaleForm + { + public SaleForm () + { + } + + public string Action { + get; + set; + } + + public FormElement[] Items { get; set; } + } +} + diff --git a/SalesCatalog/Model/Scalar.cs b/SalesCatalog/Model/Scalar.cs new file mode 100644 index 00000000..705d7111 --- /dev/null +++ b/SalesCatalog/Model/Scalar.cs @@ -0,0 +1,14 @@ +using System; + +namespace SalesCatalog.Model +{ + public abstract class Scalar + { + public Scalar () + { + } + public abstract object Quantity { get; set; } + public abstract Unit Unit{ get; set; } + } +} + diff --git a/SalesCatalog/Model/SelectInput.cs b/SalesCatalog/Model/SelectInput.cs new file mode 100644 index 00000000..3b364172 --- /dev/null +++ b/SalesCatalog/Model/SelectInput.cs @@ -0,0 +1,20 @@ +using System; +using System.Text; +using System.Web.Mvc; + +namespace SalesCatalog.Model +{ + public class SelectInput: FormInput + { + public Option[] Items; + public int SelectedIndex; + public override string ToHtml () + { + StringBuilder sb = new StringBuilder (); + foreach (Option opt in Items) + sb.Append (opt.ToHtml()); + return string.Format ("\n", Id,Name,sb.ToString()); + } + } +} + diff --git a/SalesCatalog/Model/SelectItem.cs b/SalesCatalog/Model/SelectItem.cs new file mode 100644 index 00000000..9ac5cafc --- /dev/null +++ b/SalesCatalog/Model/SelectItem.cs @@ -0,0 +1,23 @@ +using System; + +namespace SalesCatalog.Model +{ + public class SelectItem + { + public SelectItem(string t) + { + Value = t; + } + public string Value { get; set; } + public static implicit operator string(SelectItem t) + { + return t.Value; + } + public static implicit operator SelectItem(string t) + { + return new SelectItem(t); + } + + } +} + diff --git a/SalesCatalog/Model/Service.cs b/SalesCatalog/Model/Service.cs new file mode 100644 index 00000000..9c153125 --- /dev/null +++ b/SalesCatalog/Model/Service.cs @@ -0,0 +1,28 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Service : Product + { + public Service () + { + } + + public Price HourPrice { get; set; } + + #region implemented abstract members of SalesCatalog.Model.Product + public override string [] GetSalesConditions () + { + return new string [] { string.Format( + "Prix horaire de la prestation : {0} {1}", + HourPrice.Quantity.ToString(), + HourPrice.Unit.Name) } ; + } + #endregion + public override string ToString () + { + return string.Format ("[Service: HourPrice={0}]", HourPrice); + } + } +} + diff --git a/SalesCatalog/Model/StockStatus.cs b/SalesCatalog/Model/StockStatus.cs new file mode 100644 index 00000000..b4129b4e --- /dev/null +++ b/SalesCatalog/Model/StockStatus.cs @@ -0,0 +1,11 @@ +using System; + +namespace SalesCatalog.Model +{ + public enum StockStatus + { + NoStock, + InStock + } +} + diff --git a/SalesCatalog/Model/Text.cs b/SalesCatalog/Model/Text.cs new file mode 100644 index 00000000..ab223c01 --- /dev/null +++ b/SalesCatalog/Model/Text.cs @@ -0,0 +1,18 @@ +using System; + +namespace SalesCatalog.Model +{ + public class Text: FormElement + { + public string Val { + get; + set; + } + + public override string ToHtml () + { + return Val; + } + } +} + diff --git a/SalesCatalog/Model/TextInput.cs b/SalesCatalog/Model/TextInput.cs new file mode 100644 index 00000000..f3890b78 --- /dev/null +++ b/SalesCatalog/Model/TextInput.cs @@ -0,0 +1,46 @@ +using System; + +namespace SalesCatalog.Model +{ + public class TextInput:FormInput + { + public TextInput () + { + } + public TextInput (string txt) + { + text = txt; + } + string text = null; + + + public static implicit operator string(TextInput t) + { + return t.text; + } + public static implicit operator TextInput(string t) + { + return new TextInput(t); + } + public string DefaultValue { + get { + return text; + } + set { + text = (string) value; + } + } + + private bool multiline = false; + public bool MultiLine { get { return multiline; } set { multiline = value; } } + + public override string ToHtml () + { + + return MultiLine? + string.Format ("", Id,Name,DefaultValue) + : string.Format ("", Id,Name,DefaultValue); + } + } +} + diff --git a/SalesCatalog/Model/Unit.cs b/SalesCatalog/Model/Unit.cs new file mode 100644 index 00000000..8b64aea6 --- /dev/null +++ b/SalesCatalog/Model/Unit.cs @@ -0,0 +1,13 @@ +using System; + +namespace SalesCatalog.Model +{ + public abstract class Unit + { + public abstract string Name { get; } + public abstract string Description { get; } + public abstract object ConvertTo (Unit dest, object value); + public abstract bool MayConvertTo (Unit other); + } +} + diff --git a/SalesCatalog/SalesCatalog.csproj b/SalesCatalog/SalesCatalog.csproj new file mode 100644 index 00000000..9e10e684 --- /dev/null +++ b/SalesCatalog/SalesCatalog.csproj @@ -0,0 +1,102 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {90BF2234-7252-4CD5-B2A4-17501B19279B} + Library + SalesCatalog + SalesCatalog + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + none + true + bin\Release + prompt + 4 + false + + + + + + False + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SalesCatalog/Tests/TestBrands.cs b/SalesCatalog/Tests/TestBrands.cs new file mode 100644 index 00000000..ca6b6cc6 --- /dev/null +++ b/SalesCatalog/Tests/TestBrands.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using System; +using SalesCatalog.Model; + +namespace SalesCatalog.Tests +{ + [TestFixture ()] + public class TestBrands + { + [Test ()] + public void TestCaseAddRemoveBrand () + { + Catalog c = new Catalog (); + c.Brands = new Brand[0]; + Brand b=c.AddBrand ("coko"); + if (c.Brands.Length != 1) + throw new Exception ("Pas ajouté"); + if (b == null) + throw new Exception ("Renvoyé null"); + if (b.Name != "coko") + throw new Exception ("Pas le bon nom"); + if (c.Brands [0] != b) + throw new Exception ("err index 0"); + if (c.GetBrand ("coko") != b) + throw new Exception ("err get by name"); + if (!c.RemoveBrand ("coko")) + throw new Exception ("Pas supprimé"); + } + } +} + diff --git a/SalesCatalog/Tests/TestCatalogInit.cs b/SalesCatalog/Tests/TestCatalogInit.cs new file mode 100644 index 00000000..1dbeda61 --- /dev/null +++ b/SalesCatalog/Tests/TestCatalogInit.cs @@ -0,0 +1,106 @@ +using System; +using NUnit.Framework; +using SalesCatalog.XmlImplementation; +using SalesCatalog.Model; +using System.Xml.Serialization; +using System.IO; +using System.Xml; +using System.Text; + +namespace SalesCatalog.Tests +{ + [TestFixture()] + public class TestCatalogInit + { + [Test()] + public void TestSerDeserCat () + { + Catalog cat = new XmlCatalog (); + Brand b = new Brand (); + b.Logo = new ProductImage (); + b.Logo.Src = "/images/dev.png"; + b.Logo.Alt = "Dev"; + b.Name = "Developpement à la carte"; + b.Slogan = "Votre logiciel, efficace, sûr, et sur mesure"; + ProductCategory si = new ProductCategory (); + si.Name = "Systèmes d'information et sites Web"; + ProductCategory progiciel = new ProductCategory (); + progiciel.Name = "Progiciels"; + b.Categories = new ProductCategory[]{ si, progiciel }; + Service simaint = new Service (); + simaint.Name = "Maintenance logicielle"; + simaint.Description = "Correction des bugs, évolution"; + Service sidev = new Service (); + sidev.Name = "Développement logiciel"; + sidev.Description = "Votre intranet, votre site Web, sur mesure, " + + "développé en cycles courts, et en étroite collaboration avec vous"; + Service aubb = new Service (); + aubb.Name = "Audit de sécurité en black box"; + aubb.Description = "Je recherche les failles de sécurité de votre SI ou site Web, depuis l'exterieur de " + + "votre système, sans avoir eu connaissance d'aucun élément sur l'architécture de votre " + + "système"; + Service auwb = new Service (); + auwb.Name = "Audit de sécurité en white box"; + auwb.Description = "Je me déplace chez vous, pour travailler à partir de votre code source, " + + "et isoler ses failles de sécurités"; + si.Products = new Product[] { simaint, sidev, aubb, auwb }; + Service maint = new Service (); + maint.Name = "Maintenance logicielle"; + maint.Description = "Correction des bugs, évolution"; + Service dev = new Service (); + dev.Name = "Développement logiciel"; + dev.Description = "Votre progiciel, sur mesure, " + + "développé en cycles courts, et en étroite collaboration avec vous"; + progiciel.Products = new Product[] { maint, dev }; + SaleForm f = new SaleForm (); + f.Action = "/testAction"; + TextInput ticat = new TextInput ("Choose a Title"); + ticat.Id = "title" ; + ticat.MultiLine = true; + SelectInput selSize = new SelectInput (); + selSize.Id="size"; + Option o1 = new Option (); + o1.Value = "1m"; o1.Text = "1 mois"; + Option o2 = new Option (); + o2.Value = "2m"; o2.Text = "2 mois"; + Option o3 = new Option (); + o3.Value = "6m"; o3.Text = "6 mois"; + selSize.Items = new Option [] { o1, o2, o3 }; + var txt1 = new SalesCatalog.Model.Text (); + var txt2 = new SalesCatalog.Model.Text (); + txt1.Val="Choose a title : "; + txt2.Val = "[br]Choose the size : "; + f.Items = new FormElement[] {txt1,ticat,txt2,selSize}; + b.DefaultForm = f; + cat.Brands = new Brand[] { b }; + b.Categories = new ProductCategory[] { si, progiciel }; + XmlSerializer ser = + new XmlSerializer + (typeof(XmlCatalog), + new Type[]{typeof(Service), + typeof(PhysicalProduct), + typeof(Euro), + typeof(TextInput), + typeof(SalesCatalog.Model.Text), + typeof(TextInput), + typeof(SelectInput) + }); + FileInfo fi = new FileInfo ("Catalog.xml"); + if (fi.Exists) + fi.Delete (); + using (FileStream ws = fi.OpenWrite()) { + ser.Serialize (ws, cat); + } + using (FileStream rs = fi.OpenRead()) { + using (XmlTextReader rdr = new XmlTextReader(rs)) { + XmlCatalog copy = (XmlCatalog)ser.Deserialize (rdr); + if (copy.Brands == null) throw new Exception("Null brand array!"); + if (copy.Brands.Length != cat.Brands.Length) throw new Exception("Not the same count of brands"); + if (copy.Brands[0].DefaultForm.Action != cat.Brands[0].DefaultForm.Action) throw new Exception("not the same default form"); + // ... + } + } + } + } +} + diff --git a/SalesCatalog/XmlImplementation/XmlCatalog.cs b/SalesCatalog/XmlImplementation/XmlCatalog.cs new file mode 100644 index 00000000..31b2a2ba --- /dev/null +++ b/SalesCatalog/XmlImplementation/XmlCatalog.cs @@ -0,0 +1,15 @@ +using System; +using SalesCatalog.Model; +using System.Xml.Serialization; + +namespace SalesCatalog.XmlImplementation +{ + [XmlRoot] + public class XmlCatalog : Catalog + { + public XmlCatalog () + { + } + } +} + diff --git a/SalesCatalog/XmlImplementation/XmlCatalogProvider.cs b/SalesCatalog/XmlImplementation/XmlCatalogProvider.cs new file mode 100644 index 00000000..bd410b76 --- /dev/null +++ b/SalesCatalog/XmlImplementation/XmlCatalogProvider.cs @@ -0,0 +1,55 @@ +using System; +using System.Xml.Serialization; +using SalesCatalog.Model; +using System.Configuration; +using System.IO; +using System.Xml; + +namespace SalesCatalog.XmlImplementation +{ + public class XmlCatalogProvider: CatalogProvider + { + #region implemented abstract members of SalesCatalog.CatalogProvider + + public override Catalog GetCatalog () + { + // Assert fileName != null + FileInfo fi = new FileInfo (fileName); + if (fi.LastWriteTime > lastModification) + LoadCatalog (); + return catInstance; + } + + protected XmlCatalog catInstance = null; + protected DateTime lastModification; + protected string fileName = null; + #endregion + + public override void Initialize (string name, System.Collections.Specialized.NameValueCollection config) + { + fileName = config ["connection"]; + LoadCatalog (); + } + private void LoadCatalog () + { + FileInfo fi = new FileInfo (fileName); + if (!fi.Exists) + throw new Exception ( + string.Format ("Le fichier Xml decrivant le catalogue n'existe pas ({0})", fi.FullName)); + XmlSerializer xsr = new XmlSerializer (typeof(XmlCatalog),new Type[]{ + typeof(Service), + typeof(PhysicalProduct), + typeof(Euro), + typeof(Text), + typeof(TextInput), + typeof(SelectInput)}); + + using (FileStream fs = fi.OpenRead()) { + catInstance = (XmlCatalog) xsr.Deserialize (fs); + } + fileName = fi.FullName; + lastModification = fi.LastWriteTime; + } + } +} + diff --git a/SalesCatalog/catalog.xsd b/SalesCatalog/catalog.xsd new file mode 100644 index 00000000..7c9e5f73 --- /dev/null +++ b/SalesCatalog/catalog.xsd @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WebControls/Properties/AssemblyInfo.cs b/WebControls/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..ee64d87a --- /dev/null +++ b/WebControls/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Web.UI; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("WebControls")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("Paul Schneider")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] +[assembly: TagPrefix("Yavsc.WebControls", "yavsc")] diff --git a/WebControls/ResultPages.cs b/WebControls/ResultPages.cs new file mode 100644 index 00000000..c1a9c8b2 --- /dev/null +++ b/WebControls/ResultPages.cs @@ -0,0 +1,116 @@ +using System; +using System.Web; +using System.Security.Permissions; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.ComponentModel; + +namespace Yavsc.WebControls +{ + [ + AspNetHostingPermission (SecurityAction.Demand, + Level = AspNetHostingPermissionLevel.Minimal), + AspNetHostingPermission (SecurityAction.InheritanceDemand, + Level = AspNetHostingPermissionLevel.Minimal), + ParseChildren (true, "Action"), + DefaultProperty ("Action"), + ToolboxData ("<{0}:ResultPages runat=\"server\"> ") + ] + public class ResultPages: WebControl + { + public ResultPages () + { + } + + + [Bindable (true)] + [DefaultValue(10)] + public int ResultsPerPage { + get { + return (int)( ViewState["ResultsPerPage"]==null?10:ViewState["ResultsPerPage"]); + } + set { + ViewState["ResultsPerPage"]=value; + } + } + + + [Bindable (true)] + [DefaultValue(0)] + public int ResultCount { + get { + + return (int)( ViewState["ResultCount"]==null?0:ViewState["ResultCount"]); + } + set { + ViewState["ResultCount"] = value; + } + } + + [Bindable (true)] + [DefaultValue("Pages:")] + [Localizable(true)] + public string Text { + get { + + string s = (string)ViewState["Text"]; + return (s == null) ? "Pages:" : s; + } + set { + ViewState["Text"] = value; + } + } + + [Bindable (true)] + [DefaultValue("")] + public string Action { + get { + + string s = (string)ViewState["Action"]; + return (s == null) ? String.Empty : s; + } + set { + ViewState["Action"] = value; + } + } + + + [Bindable (true)] + [DefaultValue(0)] + public int CurrentPage { + get { + int i = (int)(ViewState["CurrentPage"]==null?0:ViewState["CurrentPage"]); + return i; + } + set { + ViewState["CurrentPage"] = value; + } + } + + protected override void RenderContents (HtmlTextWriter writer) + { + if (ResultCount > 0) { + writer.WriteEncodedText (Text); + int pageCount = ((ResultCount-1) / ResultsPerPage) + 1; + for (int pi = (CurrentPage < 5) ? 0 : CurrentPage - 5; pi < pageCount && pi < CurrentPage + 5; pi++) { + if (CurrentPage == pi) + writer.RenderBeginTag ("b"); + else { + writer.AddAttribute (HtmlTextWriterAttribute.Href, + string.Format (Action, pi)); + writer.RenderBeginTag ("a"); + + } + writer.Write (pi); + writer.RenderEndTag (); + writer.Write (" "); + } + writer.Write ("("+ResultCount.ToString()+" resultat(s))"); + } else { + writer.Write ("(Pas de resultat)"); + } + } + } +} + + diff --git a/WebControls/WebControls.csproj b/WebControls/WebControls.csproj new file mode 100644 index 00000000..f81a2a3a --- /dev/null +++ b/WebControls/WebControls.csproj @@ -0,0 +1,49 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356} + Library + WebControls + Yavsc.WebControls + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + False + + + False + + + + + + + + + + + + \ No newline at end of file diff --git a/WorkFlowProvider/NpgsqlContentProvider.cs b/WorkFlowProvider/NpgsqlContentProvider.cs new file mode 100644 index 00000000..ffcbb35b --- /dev/null +++ b/WorkFlowProvider/NpgsqlContentProvider.cs @@ -0,0 +1,148 @@ +using System; +using Npgsql; +using NpgsqlTypes; +using System.Configuration; +using System.Collections.Specialized; +using yavscModel.WorkFlow; + +namespace WorkFlowProvider +{ + public class NpgsqlContentProvider: IContentProvider + { + public string Order (IWFCommand c) + { + throw new NotImplementedException (); + } + + public IContent Get (string orderId) + { + throw new NotImplementedException (); + } + + public void AddDevRessource (int prjId, string userName) + { + throw new NotImplementedException (); + } + + public void AddPrjRessource(int prjId, string owner) + { + } + + public void NewRelease (int projectId, string Version) + { + throw new NotImplementedException (); + } + + string applicationName=null; + string cnxstr = null; + + public NpgsqlContentProvider () + { + Initialize("NpgsqlYavscContentProvider",ConfigurationManager.AppSettings); + } + + public void Initialize (string name, NameValueCollection config) + { + cnxstr = ConfigurationManager.ConnectionStrings [config ["connectionStringName"]].ConnectionString; + applicationName = config["applicationName"] ?? "/"; + } + + NpgsqlConnection CreateConnection () + { + return new NpgsqlConnection (cnxstr); + } + + #region IDisposable implementation + public void Dispose () + { + + } + #endregion + + #region IContentProvider implementation + + public int NewTask (int projectId, string name, string desc) + { + throw new System.NotImplementedException (); + } + + public void SetProjectName (int projectId, string name) + { + throw new System.NotImplementedException (); + } + + public void SetProjectDesc (int projectId, string desc) + { + throw new System.NotImplementedException (); + } + + public void SetTaskName (int taskId, string name) + { + throw new System.NotImplementedException (); + } + + public void SetStartDate (int taskId, DateTime d) + { + throw new System.NotImplementedException (); + } + + public void SetEndDate (int taskId, DateTime d) + { + throw new System.NotImplementedException (); + } + + public void SetTaskDesc (int taskId, string desc) + { + throw new System.NotImplementedException (); + } + + public void RemoveProject (int prjId) + { + using (var cnx = CreateConnection()) { + cnx.Open (); + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "delete from projets where id = @id"; + cmd.Parameters.Add ("@id", prjId); + cmd.ExecuteNonQuery(); + } + cnx.Close (); + } + } + + public void RemoveTask (int taskId) + { + throw new System.NotImplementedException (); + } + + public void SetManager (int projectId, string user) + { + throw new System.NotImplementedException (); + } + + public void RemoveUser (string user) + { + throw new System.NotImplementedException (); + } + + public int NewProject (string name, string desc, string ownerId) + { + int id = 0; + using (var cnx = CreateConnection()) { + cnx.Open (); + using (NpgsqlCommand cmd = cnx.CreateCommand()) { + cmd.CommandText = "insert into projets (name,managerid,ApplicatonName,prdesc) values (@name,@mid,@appname,@pdesc)"; + cmd.Parameters.Add ("@name", name); + cmd.Parameters.Add ("@mid", ownerId); + cmd.Parameters.Add ("@appname", applicationName); + cmd.Parameters.Add ("@desc", desc); + id = (int)cmd.ExecuteScalar (); + } + cnx.Close (); + } + return id; + } + #endregion + + } +} + diff --git a/WorkFlowProvider/Properties/AssemblyInfo.cs b/WorkFlowProvider/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..6344211b --- /dev/null +++ b/WorkFlowProvider/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("WorkFlowProvider")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("Paul Schneider")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/WorkFlowProvider/WFManager.cs b/WorkFlowProvider/WFManager.cs new file mode 100644 index 00000000..c9ccf4fb --- /dev/null +++ b/WorkFlowProvider/WFManager.cs @@ -0,0 +1,18 @@ +using System; +using yavscModel.WorkFlow; + +namespace WorkFlowProvider +{ + public static class WFManager + { + public static IContentProvider GetContentProviderFWC () + { + string clsName = System.Configuration.ConfigurationManager.AppSettings ["WorkflowContentProviderClass"]; + if (clsName == null) + throw new Exception ("No content provider specified in the configuration file (Application parameter \"WorkflowContentProviderClass\")"); + System.Reflection.ConstructorInfo ci = Type.GetType (clsName).GetConstructor (System.Type.EmptyTypes); + return (IContentProvider) ci.Invoke (System.Type.EmptyTypes); + } + } +} + diff --git a/WorkFlowProvider/WorkFlowProvider.csproj b/WorkFlowProvider/WorkFlowProvider.csproj new file mode 100644 index 00000000..f4713164 --- /dev/null +++ b/WorkFlowProvider/WorkFlowProvider.csproj @@ -0,0 +1,49 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {821FF72D-9F4B-4A2C-B95C-7B965291F119} + Library + WorkFlowProvider + WorkFlowProvider + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + + + + {68F5B80A-616E-4C3C-91A0-828AA40000BD} + yavscModel + + + \ No newline at end of file diff --git a/Yavsc.sln b/Yavsc.sln new file mode 100644 index 00000000..2aa90b95 --- /dev/null +++ b/Yavsc.sln @@ -0,0 +1,74 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "web\Web.csproj", "{77044C92-D2F1-45BD-80DD-AA25B311B027}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NpgsqlMRPProviders", "NpgsqlMRPProviders\NpgsqlMRPProviders.csproj", "{BBA7175D-7F92-4278-96FC-84C495A2B5A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NpgsqlBlogProvider", "NpgsqlBlogProvider\NpgsqlBlogProvider.csproj", "{C6E9E91B-97D3-48D9-8AA7-05356929E162}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SalesCatalog", "SalesCatalog\SalesCatalog.csproj", "{90BF2234-7252-4CD5-B2A4-17501B19279B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "yavscModel", "yavscModel\yavscModel.csproj", "{68F5B80A-616E-4C3C-91A0-828AA40000BD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowProvider", "WorkFlowProvider\WorkFlowProvider.csproj", "{821FF72D-9F4B-4A2C-B95C-7B965291F119}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YavscClient", "yavscclient\YavscClient.csproj", "{EEFCECE6-3B7F-4BBE-B7AF-69377AF3CF39}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebControls", "WebControls\WebControls.csproj", "{59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vscadm", "vscadm\vscadm.csproj", "{6C5E1490-E141-4ADA-84E5-6D65523D6B73}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ITContent", "ITContent\ITContent.csproj", "{88D83FC9-4158-4435-98A6-1F8F7F448B8F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356}.Release|Any CPU.Build.0 = Release|Any CPU + {68F5B80A-616E-4C3C-91A0-828AA40000BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68F5B80A-616E-4C3C-91A0-828AA40000BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68F5B80A-616E-4C3C-91A0-828AA40000BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68F5B80A-616E-4C3C-91A0-828AA40000BD}.Release|Any CPU.Build.0 = Release|Any CPU + {6C5E1490-E141-4ADA-84E5-6D65523D6B73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5E1490-E141-4ADA-84E5-6D65523D6B73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5E1490-E141-4ADA-84E5-6D65523D6B73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C5E1490-E141-4ADA-84E5-6D65523D6B73}.Release|Any CPU.Build.0 = Release|Any CPU + {77044C92-D2F1-45BD-80DD-AA25B311B027}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77044C92-D2F1-45BD-80DD-AA25B311B027}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77044C92-D2F1-45BD-80DD-AA25B311B027}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77044C92-D2F1-45BD-80DD-AA25B311B027}.Release|Any CPU.Build.0 = Release|Any CPU + {821FF72D-9F4B-4A2C-B95C-7B965291F119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {821FF72D-9F4B-4A2C-B95C-7B965291F119}.Debug|Any CPU.Build.0 = Debug|Any CPU + {821FF72D-9F4B-4A2C-B95C-7B965291F119}.Release|Any CPU.ActiveCfg = Release|Any CPU + {821FF72D-9F4B-4A2C-B95C-7B965291F119}.Release|Any CPU.Build.0 = Release|Any CPU + {88D83FC9-4158-4435-98A6-1F8F7F448B8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88D83FC9-4158-4435-98A6-1F8F7F448B8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88D83FC9-4158-4435-98A6-1F8F7F448B8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88D83FC9-4158-4435-98A6-1F8F7F448B8F}.Release|Any CPU.Build.0 = Release|Any CPU + {90BF2234-7252-4CD5-B2A4-17501B19279B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90BF2234-7252-4CD5-B2A4-17501B19279B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90BF2234-7252-4CD5-B2A4-17501B19279B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90BF2234-7252-4CD5-B2A4-17501B19279B}.Release|Any CPU.Build.0 = Release|Any CPU + {BBA7175D-7F92-4278-96FC-84C495A2B5A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBA7175D-7F92-4278-96FC-84C495A2B5A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBA7175D-7F92-4278-96FC-84C495A2B5A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BBA7175D-7F92-4278-96FC-84C495A2B5A6}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E9E91B-97D3-48D9-8AA7-05356929E162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E9E91B-97D3-48D9-8AA7-05356929E162}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E9E91B-97D3-48D9-8AA7-05356929E162}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E9E91B-97D3-48D9-8AA7-05356929E162}.Release|Any CPU.Build.0 = Release|Any CPU + {EEFCECE6-3B7F-4BBE-B7AF-69377AF3CF39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEFCECE6-3B7F-4BBE-B7AF-69377AF3CF39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEFCECE6-3B7F-4BBE-B7AF-69377AF3CF39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEFCECE6-3B7F-4BBE-B7AF-69377AF3CF39}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = web\Web.csproj + EndGlobalSection +EndGlobal diff --git a/mkReleaseSourceCode.sh b/mkReleaseSourceCode.sh new file mode 100644 index 00000000..ae13d4bf --- /dev/null +++ b/mkReleaseSourceCode.sh @@ -0,0 +1 @@ +git archive --format=tar --prefix=yavsc-1.1/ 1.1 | bzip2 > yavsc-1.1.tar.bz2 diff --git a/noavatar.xcf b/noavatar.xcf new file mode 100644 index 0000000000000000000000000000000000000000..e182ad80fe0ecee08a5f0c4c6cd6b57d238e62cd GIT binary patch literal 5885 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 c{>mug=#$+JP#G + + + Debug + AnyCPU + 10.0.0 + 2.0 + {6C5E1490-E141-4ADA-84E5-6D65523D6B73} + Exe + vscadm + vscadm + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + full + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/Admin/DataManager.cs b/web/Admin/DataManager.cs new file mode 100644 index 00000000..cc24a375 --- /dev/null +++ b/web/Admin/DataManager.cs @@ -0,0 +1,81 @@ +using System; +using System.Diagnostics; +using System.IO; +using yavscModel.Admin; +using Npgsql.Web.Blog; + +namespace Yavsc.Admin +{ + public class DataManager + { + DataAccess da; + public DataManager (DataAccess datac) + { + da = datac; + } + + public Export CreateBackup () + { + Environment.SetEnvironmentVariable("PGPASSWORD", da.Password); + Export e = new Export (); + string fileName = da.BackupPrefix + "-" + DateTime.Now.ToString ("yyyyMMdd"); + FileInfo ofi = new FileInfo (fileName); + e.FileName = ofi.FullName; + Exec ("pg_dump", string.Format ( + "-wb -Z3 -f {0} -Fd -h {1} -U {2} -p {3} {4}", + fileName, da.Host, da.Dbuser, da.Port, da.Dbname ),e); + return e; + } + + private void Exec(string name, string args, TaskOutput output) + { + ProcessStartInfo Pinfo = + new ProcessStartInfo (name,args); + Pinfo.RedirectStandardError = true; + Pinfo.RedirectStandardOutput = true; + Pinfo.CreateNoWindow = true; + Pinfo.UseShellExecute = false; + using (Process p = new Process ()) { + p.EnableRaisingEvents = true; + p.StartInfo = Pinfo; + p.Start (); + p.WaitForExit (); + output.Error = p.StandardError.ReadToEnd (); + output.Message = p.StandardOutput.ReadToEnd (); + output.ExitCode = p.ExitCode; + p.Close (); + } + } + public TaskOutput Restore (string fileName, bool dataOnly) + { + Environment.SetEnvironmentVariable("PGPASSWORD", da.Password); + var t = new TaskOutput (); + Exec ("pg_restore", (dataOnly?"-a ":"")+string.Format ( + "-1 -w -Fd -O -h {0} -U {1} -p {2} -d {3} {4}", + da.Host, da.Dbuser, da.Port, da.Dbname, fileName ),t); + return t; + } + public TaskOutput CreateDb () + { + return Restore ("freshinstall", false); + } + public Export TagBackup (string filename, string [] tags) + { + /* FileInfo fi = new FileInfo (filename); + using (FileStream s = fi.OpenWrite ()) { + + } */ + throw new NotImplementedException (); + } + public TaskOutput TagRestore (string fileName) + { + Environment.SetEnvironmentVariable ("PGPASSWORD", da.Password); + var t = new TaskOutput (); + Exec ("pg_restore", string.Format ( + "-a -w -Fd -O -h {0} -U {1} -p {2} -d {3} {4}", + da.Host, da.Dbuser, da.Port, da.Dbname, fileName ),t); + return t; + } + } +} + diff --git a/web/Admin/Export.cs b/web/Admin/Export.cs new file mode 100644 index 00000000..046512f7 --- /dev/null +++ b/web/Admin/Export.cs @@ -0,0 +1,14 @@ +using System; +using System.ComponentModel; + +namespace Yavsc.Admin +{ + public class Export: TaskOutput + { + public Export () + { + } + public string FileName { get; set; } + } +} + diff --git a/web/Admin/TaskOutput.cs b/web/Admin/TaskOutput.cs new file mode 100644 index 00000000..b84225ab --- /dev/null +++ b/web/Admin/TaskOutput.cs @@ -0,0 +1,12 @@ +using System; +using System.ComponentModel; + +namespace Yavsc.Admin +{ + public class TaskOutput { + public string Message { get; set; } + public string Error { get; set; } + public int ExitCode { get; set; } + } + +} diff --git a/web/AssemblyInfo.cs b/web/AssemblyInfo.cs new file mode 100644 index 00000000..08760d78 --- /dev/null +++ b/web/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Yavsc")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("paul schneider")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.2.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/web/Basket/Basket.cs b/web/Basket/Basket.cs new file mode 100644 index 00000000..bcfb9ec3 --- /dev/null +++ b/web/Basket/Basket.cs @@ -0,0 +1,17 @@ +using System; +using SalesCatalog.Model; +using System.Collections.Generic; + +namespace Yavsc.Basket +{ + public class Basket + { + public Basket () + { + } + + public void Add(Product p) + { + } + } +} diff --git a/web/CatExts/WebCatalogExtensions.cs b/web/CatExts/WebCatalogExtensions.cs new file mode 100644 index 00000000..01e07b9f --- /dev/null +++ b/web/CatExts/WebCatalogExtensions.cs @@ -0,0 +1,80 @@ +using System; +using System.Web; +using SalesCatalog; +using SalesCatalog.Model; +using System.Text; +using System.Web.Mvc; +using System.Web.Routing; +using System.Web.Mvc.Html; + +namespace Yavsc.CatExts +{ + public static class WebCatalogExtensions + { + public static string CommandForm(this HtmlHelper helper, Product pos,string atc="Add to backet") { + StringBuilder sb = new StringBuilder (); + sb.Append (helper.ValidationSummary ()); + TagBuilder ft = new TagBuilder ("form"); + ft.Attributes.Add("action","/FrontOffice/Command"); + ft.Attributes.Add("method","post"); + ft.Attributes.Add("enctype","multipart/form-data"); + TagBuilder fieldset = new TagBuilder ("fieldset"); + + TagBuilder legend = new TagBuilder ("legend"); + legend.SetInnerText (pos.Name); + TagBuilder para = new TagBuilder ("p"); + + StringBuilder sbfc = new StringBuilder (); + if (pos.CommandForm != null) + foreach (FormElement e in pos.CommandForm.Items) { + sbfc.Append (e.ToHtml ()); + sbfc.Append ("
\n"); + } + sbfc.Append ( + string.Format( + "
\n", + atc + )); + + sbfc.Append (helper.Hidden ("ref", pos.Reference)); + para.InnerHtml = sbfc.ToString (); + fieldset.InnerHtml = legend.ToString ()+"\n"+para.ToString (); + ft.InnerHtml = fieldset.ToString (); + sb.Append (ft.ToString ()); + return sb.ToString (); + } + public static string CommandForm(this HtmlHelper helper, Product pos,string atc="Add to backet") { + StringBuilder sb = new StringBuilder (); + sb.Append (helper.ValidationSummary ()); + TagBuilder ft = new TagBuilder ("form"); + ft.Attributes.Add("action","/FrontOffice/Command"); + ft.Attributes.Add("method","post"); + ft.Attributes.Add("enctype","multipart/form-data"); + TagBuilder fieldset = new TagBuilder ("fieldset"); + + TagBuilder legend = new TagBuilder ("legend"); + legend.SetInnerText (pos.Name); + TagBuilder para = new TagBuilder ("p"); + + StringBuilder sbfc = new StringBuilder (); + if (pos.CommandForm != null) + foreach (FormElement e in pos.CommandForm.Items) { + sbfc.Append (e.ToHtml ()); + sbfc.Append ("
\n"); + } + sbfc.Append ( + string.Format( + "
\n",atc)); + sbfc.Append (helper.Hidden ("ref", pos.Reference)); + para.InnerHtml = sbfc.ToString (); + fieldset.InnerHtml = legend.ToString ()+"\n"+para.ToString (); + ft.InnerHtml = fieldset.ToString (); + sb.Append (ft.ToString ()); + return sb.ToString (); + } + + + + } +} + diff --git a/web/Catalog.xml b/web/Catalog.xml new file mode 100644 index 00000000..4095cd74 --- /dev/null +++ b/web/Catalog.xml @@ -0,0 +1,56 @@ + + + + + shdsi + Votre logiciel, efficace, sûr, et sur mesure + + /images/logoDev.png + + + + + Systèmes d'information et sites Web + ntic + + + Développement + Votre Extranet, Intranet, + site Web, sur mesure, élégant et efficace, au look racé, accessible, + et développé en cycles courts + nticdev + + + Maintenance + Correction des anomalies, réalisation des évolutions, prévision des besoins + nticmaint + + + + + + /Commande + + + Entrez un commentaire : + + + comment + Commentaire + + + Choisissez le type d'intervention souhaité: + + + ad + + à distance + sur site + + 0 + + + + + + diff --git a/web/Controllers/AccountController.cs b/web/Controllers/AccountController.cs new file mode 100644 index 00000000..8685a59c --- /dev/null +++ b/web/Controllers/AccountController.cs @@ -0,0 +1,369 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Mail; +using System.Web; +using System.Web.Configuration; +using System.Web.Mvc; +using System.Web.Mvc.Ajax; +using System.Web.Profile; +using System.Web.Security; +using Yavsc; +using yavscModel.RolesAndMembers; +using Yavsc.Helpers; + +namespace Yavsc.Controllers +{ + public class AccountController : Controller + { + private static string registrationMessage = + WebConfigurationManager.AppSettings ["RegistrationMessage"]; + + string avatarDir = "~/avatars"; + + public string AvatarDir { + get { return avatarDir; } + set { avatarDir = value; } + } + + public ActionResult Index () + { + return View (); + } + + public ActionResult Login (string returnUrl) + { + ViewData ["returnUrl"] = returnUrl; + return View (); + } + + [Authorize] + public ActionResult Profile(Profile model) + { + ViewData ["UserName"] = Membership.GetUser ().UserName; + model.FromProfileBase(HttpContext.Profile); + return View (model); + } + // TODO [ValidateAntiForgeryToken] + public ActionResult DoLogin (LoginModel model, string returnUrl) + { + if (ModelState.IsValid) { + if (Membership.ValidateUser (model.UserName, model.Password)) { + FormsAuthentication.SetAuthCookie (model.UserName, model.RememberMe); + if (returnUrl != null) + return Redirect (returnUrl); + else return View ("Index"); + } else { + ModelState.AddModelError ("UserName", "The user name or password provided is incorrect."); + } + } + + ViewData ["returnUrl"] = returnUrl; + + // If we got this far, something failed, redisplay form + return View ("Login",model); + } + + public ActionResult Register (RegisterViewModel model, string returnUrl) + { + ViewData["returnUrl"] = returnUrl; + if (Request.RequestType == "GET") { + foreach (string k in ModelState.Keys) + ModelState [k].Errors.Clear (); + return View (model); + } + if (ModelState.IsValid) { + if (model.ConfirmPassword != model.Password) + { + ModelState.AddModelError("ConfirmPassword","Veuillez confirmer votre mot de passe"); + return View (model); + } + + MembershipCreateStatus mcs; + var user = Membership.CreateUser ( + model.UserName, + model.Password, + model.Email, + null, + null, + false, + out mcs); + switch (mcs) { + case MembershipCreateStatus.DuplicateEmail: + ModelState.AddModelError("Email", "Cette adresse e-mail correspond " + + "à un compte utilisateur existant"); + return View (model); + case MembershipCreateStatus.DuplicateUserName: + ModelState.AddModelError("UserName", "Ce nom d'utilisateur est " + + "déjà enregistré"); + return View (model); + case MembershipCreateStatus.Success: + FileInfo fi = new FileInfo ( + Server.MapPath(registrationMessage)); + if (!fi.Exists) { + ViewData["Error"] = "Erreur inattendue (pas de corps de message à envoyer)"; + return View (model); + } + using (StreamReader sr = fi.OpenText()) { + string body = sr.ReadToEnd(); + body = body.Replace("<%SiteName%>",YavscHelpers.SiteName); + body = body.Replace("<%UserName%>",user.UserName); + body = body.Replace("<%UserActivatonUrl%>", + string.Format("<{0}://{1}/Account/Validate/{2}?key={3}", + Request.Url.Scheme, + Request.Url.Authority, + user.UserName, + user.ProviderUserKey.ToString())); + using (MailMessage msg = new MailMessage( + HomeController.Admail,user.Email, + string.Format("Validation de votre compte {0}",YavscHelpers.SiteName), + body)) + { + using (SmtpClient sc = new SmtpClient()) + { + sc.Send (msg); + } + } + + ViewData ["username"] = user.UserName; + ViewData ["email"] = user.Email; + return View ("RegistrationPending"); + } + default: + ViewData["Error"] = "Une erreur inattendue s'est produite" + + "a l'enregistrement de votre compte utilisateur" + + string.Format("({0}).",mcs.ToString()) + + "Veuillez pardonner la gêne" + + "occasionnée"; + return View (model); + } + + } + return View (model); + } + + public ActionResult ChangePasswordSuccess () + { + return View (); + } + + [HttpGet] + [Authorize] + public ActionResult ChangePassword() + { + return View(); + } + + [Authorize] + [HttpPost] + public ActionResult ChangePassword (ChangePasswordModel model) + { + if (ModelState.IsValid) { + + // ChangePassword will throw an exception rather + // than return false in certain failure scenarios. + bool changePasswordSucceeded; + try { + var users = Membership.FindUsersByName (model.Username); + + if (users.Count > 0) { + MembershipUser user = Membership.GetUser (model.Username,true); + changePasswordSucceeded = user.ChangePassword (model.OldPassword, model.NewPassword); + } else { + changePasswordSucceeded = false; + } + } catch (Exception) { + changePasswordSucceeded = false; + } + + if (changePasswordSucceeded) { + return RedirectToAction ("ChangePasswordSuccess"); + } else { + ModelState.AddModelError ("Password", "The current password is incorrect or the new password is invalid."); + } + } + + // If we got this far, something failed, redisplay form + return View (model); + } + + [Authorize()] + public ActionResult UserList () + { + MembershipUserCollection c = Membership.GetAllUsers (); + return View (c); + } + + private const string adminRoleName = "Admin"; + + [Authorize()] + public ActionResult Admin (NewAdminModel model) + { + string currentUser = Membership.GetUser ().UserName; + if (ModelState.IsValid) { + Roles.AddUserToRole (model.UserName, adminRoleName); + ViewData ["Message"] = model.UserName + " was added to the role '" + adminRoleName + "'"; + } else { + if (!Roles.RoleExists (adminRoleName)) { + Roles.CreateRole (adminRoleName); + string.Format ("The role '{0}' has just been created. ", + adminRoleName); + } + string [] admins = Roles.GetUsersInRole (adminRoleName); + if (admins.Length > 0) { + if (! admins.Contains (Membership.GetUser ().UserName)) { + ModelState.Remove("UserName"); + ModelState.AddModelError("UserName", "You're not administrator!"); + return View ("Index"); + } + } else { + Roles.AddUserToRole (currentUser, adminRoleName); + admins = new string[] { currentUser }; + ViewData ["Message"] += string.Format ( + "There was no user in the 'Admin' role. You ({0}) was just added as the firt user in the 'Admin' role. ", currentUser); + } + + List users = new List (); + foreach (MembershipUser u in Membership.GetAllUsers ()) { + var i = new SelectListItem (); + i.Text = string.Format ("{0} <{1}>", u.UserName, u.Email); + i.Value = u.UserName; + users.Add (i); + } + ViewData ["useritems"] = users; + ViewData ["admins"] = admins; + } + return View (model); + } + + [Authorize()] + public ActionResult RoleList () + { + return View (Roles.GetAllRoles ()); + } + + + [Authorize(Roles="Admin")] + public ActionResult RemoveFromRole(string username, string rolename, string returnUrl) + { + Roles.RemoveUserFromRole(username,rolename); + return Redirect(returnUrl); + } + + [Authorize(Roles="Admin")] + public ActionResult RemoveUser (string username, string submitbutton) + { + if (submitbutton == "Supprimer") { + Membership.DeleteUser (username); + ViewData["Message"]= + string.Format("utilisateur \"{0}\" supprimé",username); + } + return RedirectToAction("UserList"); + } + [Authorize] + [HttpPost] + //public ActionResult UpdateProfile(HttpPostedFileBase Avatar, string Address, string CityAndState, string ZipCode, string Country, string WebSite) + public ActionResult UpdateProfile(Profile model, HttpPostedFileBase AvatarFile) + { + string username = Membership.GetUser ().UserName; + + if (AvatarFile != null) { + + if (AvatarFile.ContentType == "image/png") { + // byte[] img = new byte[AvatarFile.ContentLength]; + // AvatarFile.InputStream.Read (img, 0, AvatarFile.ContentLength); + // model.Avatar = img; + + string avdir=Server.MapPath (AvatarDir); + string avpath=Path.Combine(avdir,username+".png"); + AvatarFile.SaveAs (avpath); + } else + ModelState.AddModelError ("Avatar", + string.Format ("Image type {0} is not supported (suported formats : {1})", + AvatarFile.ContentType, "image/png") + ); + } + if (ModelState.IsValid) { + HttpContext.Profile.SetPropertyValue ( + "Address", model.Address); + HttpContext.Profile.SetPropertyValue ( + "BlogTitle", model.BlogTitle); + HttpContext.Profile.SetPropertyValue ( + "BlogVisible", model.BlogVisible); + HttpContext.Profile.SetPropertyValue ( + "CityAndState", model.CityAndState); + HttpContext.Profile.SetPropertyValue ( + "Country", model.Country); + HttpContext.Profile.SetPropertyValue ( + "WebSite", model.WebSite); + + } + // HttpContext.Profile.SetPropertyValue("Avatar",Avatar); + return RedirectToAction ("Profile"); + } + + [Authorize(Roles="Admin")] + public ActionResult RemoveRole (string rolename, string submitbutton) + { + if (submitbutton == "Supprimer") + { + Roles.DeleteRole(rolename); + } + return RedirectToAction("RoleList"); + } + + [Authorize(Roles="Admin")] + public ActionResult RemoveRoleQuery(string rolename) + { + ViewData["roletoremove"] = rolename; + return View (); + } + + [Authorize(Roles="Admin")] + public ActionResult RemoveUserQuery(string username) + { + ViewData["usertoremove"] = username; + return UserList(); + } + + [Authorize] + public ActionResult Logout (string returnUrl) + { + FormsAuthentication.SignOut(); + return Redirect(returnUrl); + } + + [Authorize(Roles="Admin")] + public ActionResult AddRole () + { + return View (); + } + + [Authorize(Roles="Admin")] + public ActionResult DoAddRole (string rolename) + { + Roles.CreateRole(rolename); + ViewData["Message"] = "Rôle créé : "+rolename; + return View (); + } + + public ActionResult Validate (string id, string key) + { + MembershipUser u = Membership.GetUser (id, false); + if (u == null) { + ViewData ["Error"] = + string.Format ("Cet utilisateur n'existe pas ({0})", id); + } + else + if (u.ProviderUserKey.ToString () == key) { + u.IsApproved = true; + Membership.UpdateUser(u); + ViewData["Message"] = + string.Format ("La création de votre compte ({0}) est validée.", id); + } + else ViewData["Error"] = "La clé utilisée pour valider ce compte est incorrecte"; + return View (); + } + } +} diff --git a/web/Controllers/BackOfficeController.cs b/web/Controllers/BackOfficeController.cs new file mode 100644 index 00000000..66c7c484 --- /dev/null +++ b/web/Controllers/BackOfficeController.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using Yavsc.Admin; +using yavscModel.Admin; + + +namespace Yavsc.Controllers +{ + public class BackOfficeController : Controller + { + [Authorize(Roles="Admin")] + public ActionResult Index(DataAccess model) + { + return View (model); + } + [Authorize(Roles="Admin")] + public ActionResult Backups(DataAccess model) + { + return View (model); + } + + [Authorize(Roles="Admin")] + public ActionResult CreateBackup(DataAccess datac) + { + if (datac != null) { + if (ModelState.IsValid) { + if (string.IsNullOrEmpty (datac.Password)) + ModelState.AddModelError ("Password", "Invalid passord"); + DataManager ex = new DataManager (datac); + Export e = ex.CreateBackup (); + if (e.ExitCode > 0) + ModelState.AddModelError ("Password", "Operation Failed"); + return View ("BackupCreated", e); + } + } else { + datac = new DataAccess (); + } + return View (datac); + } + + [Authorize(Roles="Admin")] + public ActionResult CreateUserBackup(DataAccess datac,string username) + { +throw new NotImplementedException(); + } + + + [Authorize(Roles="Admin")] + public ActionResult Restore(DataAccess datac,string backupName,bool dataOnly=true) + { + ViewData ["BackupName"] = backupName; + if (ModelState.IsValid) { + DataManager mgr = new DataManager (datac); + ViewData ["BackupName"] = backupName; + ViewData ["DataOnly"] = dataOnly; + TaskOutput t = mgr.Restore (backupName,dataOnly); + return View ("Restored", t); + } + return View (datac); + } + + } +} diff --git a/web/Controllers/BasketController.cs b/web/Controllers/BasketController.cs new file mode 100644 index 00000000..410a3e70 --- /dev/null +++ b/web/Controllers/BasketController.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Security; + +namespace Yavsc.Controllers +{ + public class BasketController : Controller + { + public ActionResult Index() + { + return View (); + } + + public ActionResult Details(int id) + { + return View (); + } + + public ActionResult Create() + { + var user = Membership.GetUser (); + var username = (user != null)?user.UserName:Request.AnonymousID; + // get an existing basket + + return View (); + } + + [HttpPost] + public ActionResult Create(FormCollection collection) + { + try { + return RedirectToAction ("Index"); + } catch { + return View (); + } + } + + public ActionResult Edit(int id) + { + return View (); + } + + [HttpPost] + public ActionResult Edit(int id, FormCollection collection) + { + try { + return RedirectToAction ("Index"); + } catch { + return View (); + } + } + + public ActionResult Delete(int id) + { + return View (); + } + + [HttpPost] + public ActionResult Delete(int id, FormCollection collection) + { + try { + return RedirectToAction ("Index"); + } catch { + return View (); + } + } + } +} \ No newline at end of file diff --git a/web/Controllers/BlogsController.cs b/web/Controllers/BlogsController.cs new file mode 100644 index 00000000..9d5fc9c2 --- /dev/null +++ b/web/Controllers/BlogsController.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Net.Mime; +using System.Runtime.Serialization.Formatters.Binary; +using System.Web; +using System.Web.Configuration; +using System.Web.Mvc; +using System.Web.Mvc.Ajax; +using System.Web.Profile; +using System.Web.Security; +using CodeKicker.BBCode; +using Npgsql.Web.Blog; +using Npgsql.Web.Blog.DataModel; +using Yavsc; +using yavscModel; + +namespace Yavsc.Controllers +{ + public class BlogsController : Controller + { + string defaultAvatarMimetype; + private string sitename = + WebConfigurationManager.AppSettings ["Name"]; + string avatarDir = "~/avatars"; + + public string AvatarDir { + get { return avatarDir; } + set { avatarDir = value; } + } + + public BlogsController () + { + string[] defaultAvatarSpec = ConfigurationManager.AppSettings.Get ("DefaultAvatar").Split (';'); + if (defaultAvatarSpec.Length != 2) + throw new ConfigurationErrorsException ("the DefaultAvatar spec should be found as ; "); + defaultAvatar = defaultAvatarSpec [0]; + defaultAvatarMimetype = defaultAvatarSpec [1]; + } + + public ActionResult Index (string user = null, string title = null, int pageIndex=0, int pageSize=10) + { + if (string.IsNullOrEmpty (user)) { + ViewData ["Message"] = "Blogs"; + return BlogList (pageIndex, pageSize); + } else { + MembershipUser u = Membership.GetUser (user, false); + if (u == null) { + ModelState.AddModelError ("UserName", + string.Format ("Utilisateur inconu : {0}", user)); + return BlogList (); + } else { + if (string.IsNullOrEmpty (title)) + return UserPosts (user, pageIndex, pageSize); + return UserPost (user, title); + } + } + } + + public ActionResult BlogList (int pageIndex = 0, int pageSize = 10) + { + ViewData ["SiteName"] = sitename; + int totalRecords; + BlogEntryCollection bs = BlogManager.LastPosts (pageIndex, pageSize, out totalRecords); + ViewData ["RecordCount"] = totalRecords; + ViewData ["PageSize"] = pageSize; + ViewData ["PageIndex"] = pageIndex; + return View ("Index", bs); + } + + [HttpGet] + public ActionResult UserPosts (string user, int pageIndex = 0, int pageSize = 10) + { + int tr; + MembershipUser u = Membership.GetUser (); + FindBlogEntryFlags sf = FindBlogEntryFlags.MatchUserName; + ViewData ["SiteName"] = sitename; + ViewData ["BlogUser"] = user; + if (u != null) + if (u.UserName == user) + sf |= FindBlogEntryFlags.MatchInvisible; + BlogEntryCollection c = BlogManager.FindPost (user, sf, pageIndex, pageSize, out tr); + ViewData ["BlogTitle"] = BlogTitle (user); + ViewData ["PageIndex"] = pageIndex; + ViewData ["PageSize"] = pageSize; + ViewData ["RecordCount"] = tr; + return View ("UserPosts", c); + + } + + [Authorize] + public ActionResult RemoveComment(long cmtid) + { + long postid = BlogManager.RemoveComment (cmtid); + return UserPost (postid); + } + + private ActionResult UserPost (long id) + { + ViewData ["PostId"] = id; + + BlogEntry e = BlogManager.GetPost (id); + return UserPost (e); + } + + private ActionResult UserPost (BlogEntry e) + { + if (e == null) + return View ("TitleNotFound"); + MembershipUser u = Membership.GetUser (); + if (u != null) + ViewData ["UserName"] = u.UserName; + if (!e.Visible) { + if (u==null) + return View ("TitleNotFound"); + else if (u.UserName!=e.UserName) + return View ("TitleNotFound"); + } + ViewData ["BlogTitle"] = BlogTitle (e.UserName); + ViewData ["Comments"] = BlogManager.GetComments (e.Id); + return View ("UserPost", e); + } + + public ActionResult UserPost (string user, string title) + { + ViewData ["BlogUser"] = user; + ViewData ["PostTitle"] = title; + int postid = 0; + if (string.IsNullOrEmpty (title)) { + if (int.TryParse (user, out postid)) { + return UserPost (BlogManager.GetPost (postid)); + } + } + return UserPost (BlogManager.GetPost (user, title)); + } + + [Authorize] + public ActionResult Post (string user, string title) + { + ViewData ["SiteName"] = sitename; + string un = Membership.GetUser ().UserName; + if (String.IsNullOrEmpty (user)) + user = un; + if (un != user) + ViewData ["Message"] = string.Format ("Vous n'êtes pas {0}!", user); + ViewData ["UserName"] = un; + return View (new BlogEditEntryModel { Title = title }); + } + + [Authorize] + public ActionResult ValidatePost (BlogEditEntryModel model) + { + string username = Membership.GetUser ().UserName; + ViewData ["SiteName"] = sitename; + ViewData ["BlogUser"] = username; + if (ModelState.IsValid) { + if (!model.Preview) { + BlogManager.Post (username, model.Title, model.Content, model.Visible); + return UserPost (username, model.Title); + } + } + return View ("Post", model); + } + + [Authorize] + public ActionResult ValidateEdit (BlogEditEntryModel model) + { + ViewData ["SiteName"] = sitename; + ViewData ["BlogUser"] = Membership.GetUser ().UserName; + if (ModelState.IsValid) { + if (!model.Preview) { + BlogManager.UpdatePost (model.Id, model.Content, model.Visible); + return UserPost (model); + } + } + return View ("Edit", model); + } + + [Authorize] + public ActionResult Edit (BlogEditEntryModel model) + { + if (model != null) { + string user = Membership.GetUser ().UserName; + ViewData ["BlogTitle"] = this.BlogTitle (user); + ViewData ["UserName"] = user; + if (model.UserName == null) { + model.UserName = user; + BlogEntry e = BlogManager.GetPost (model.UserName, model.Title); + if (e == null) { + return View ("TitleNotFound"); + } else { + model = new BlogEditEntryModel (e); + ModelState.Clear (); + this.TryValidateModel (model); + } + } else if (model.UserName != user) { + return View ("TitleNotFound"); + } + } + return View (model); + } + + private string BlogTitle (string user) + { + return string.Format ("{0}'s blog", user); + } + public ActionResult Comment (BlogEditCommentModel model) { + string username = Membership.GetUser ().UserName; + ViewData ["SiteName"] = sitename; + if (ModelState.IsValid) { + if (!model.Preview) { + BlogManager.Comment(username, model.PostId, model.CommentText, model.Visible); + return UserPost (model.PostId); + } + } + return View (model); + } + + string defaultAvatar; + + [AcceptVerbs (HttpVerbs.Get)] + public ActionResult Avatar (string user) + { + string avpath = Path.Combine ( + Server.MapPath (AvatarDir), user + ".png"); + FileInfo fia = new FileInfo (avpath); + if (!fia.Exists) + fia = new FileInfo (Server.MapPath (defaultAvatar)); + return File (fia.OpenRead (), defaultAvatarMimetype); + } + + [Authorize] + public ActionResult Remove (string user, string title, string returnUrl) + { + if (!Roles.IsUserInRole ("Admin")) { + string rguser = Membership.GetUser ().UserName; + if (rguser != user) { + ModelState.AddModelError ( + "Title", string.Format ( + "Vous n'avez pas de droits sur le Blog de {0}", + user)); + return Return (returnUrl); + } + } + BlogEntry e = BlogManager.GetPost (user, title); + if (e == null) { + ModelState.AddModelError ( + "Title", + string.Format ( + "Aucun post portant le titre \"{0}\" pour l'utilisateur {1}", + title, user)); + return Return (returnUrl); + } + BlogManager.RemovePost (user, title); + return Return (returnUrl); + } + + private ActionResult Return (string returnUrl) + { + if (!string.IsNullOrEmpty (returnUrl)) + return Redirect (returnUrl); + else + return RedirectToAction ("Index"); + } + } +} + diff --git a/web/Controllers/Commande.cs b/web/Controllers/Commande.cs new file mode 100644 index 00000000..007dec84 --- /dev/null +++ b/web/Controllers/Commande.cs @@ -0,0 +1,21 @@ +using System; +using Yavsc; +using SalesCatalog; +using SalesCatalog.Model; +using System.Web.Mvc; +using System.Web; +using System.Text.RegularExpressions; +using System.IO; +using Yavsc.Controllers; + +namespace Yavsc.Controllers +{ + public class Commande + { + public Commande(FormCollection collection) + { + + } + } +} + diff --git a/web/Controllers/FileSystemController.cs b/web/Controllers/FileSystemController.cs new file mode 100644 index 00000000..6045fc94 --- /dev/null +++ b/web/Controllers/FileSystemController.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.IO; +using System.Web.Security; +using FileSystem; +using System.Text.RegularExpressions; + +namespace Yavsc.Controllers +{ + public class FileSystemController : Controller + { + private static string usersDir ="users"; + + public static string UsersDir { + get { + return usersDir; + } + } + + [Authorize] + public ActionResult Index() + { + string user = Membership.GetUser ().UserName; + ViewData ["UserName"] = user; + DirectoryInfo di = new DirectoryInfo ( + Path.Combine( + UsersDir, + user)); + if (!di.Exists) + di.Create (); + return View (new FileInfoCollection( di.GetFiles())); + } + + public ActionResult Details(string id) + { + foreach (char x in Path.GetInvalidPathChars()) { + if (id.Contains (x)) { + ViewData ["Message"] = + string.Format ( + "Something went wrong following the following path : {0} (\"{1}\")", + id,x); + return RedirectToAction ("Index"); + } + } + string fpath = Path.Combine (BaseDir, id); + ViewData["Content"] = Url.Content (fpath); + FileInfo fi = new FileInfo (fpath); + + return View (fi); + } + + public ActionResult Create() + { + return View (); + } + [HttpPost] + [Authorize] + public ActionResult Create(FormCollection collection) + { + try { + string fnre = "[A-Za-z0-9~\\-.]+"; + HttpFileCollectionBase hfc = Request.Files; + + for (int i=0; iFile name '{0}' refused

",hfc[i].FileName); + ModelState.AddModelError( + "AFile", + string.Format( + "The file name {0} dosn't match an acceptable file name {1}", + hfc[i].FileName,fnre)) + ; + return View(); + } + } + for (int i=0; iFile name '{0}' saved

",hfc[i].FileName); + } + return RedirectToAction ("Index","FileSystem"); + } catch (Exception e) { + ViewData ["Message"] = "Exception:"+e.Message; + return View (); + } + } + + + public static string BaseDir { get { return Path.Combine (UsersDir, Membership.GetUser ().UserName); } } + + public ActionResult Edit(int id) + { + return View (); + } + + [HttpPost] + public ActionResult Edit(int id, FormCollection collection) + { + try { + return RedirectToAction ("Index"); + } catch { + return View (); + } + } + + public ActionResult Delete(int id) + { + return View (); + } + + [HttpPost] + public ActionResult Delete(int id, FormCollection collection) + { + try { + return RedirectToAction ("Index"); + } catch { + return View (); + } + } + } +} \ No newline at end of file diff --git a/web/Controllers/FrontOfficeApiController.cs b/web/Controllers/FrontOfficeApiController.cs new file mode 100644 index 00000000..57ced4f3 --- /dev/null +++ b/web/Controllers/FrontOfficeApiController.cs @@ -0,0 +1,85 @@ +using System; +using Yavsc; +using SalesCatalog; +using SalesCatalog.Model; +using System.Web.Routing; +using System.Threading.Tasks; +using System.Diagnostics; +using System.Web.Http; +using System.Net.Http; +using System.Web; +using System.Linq; +using System.IO; +using System.Net; + +namespace Yavsc.ApiControllers +{ + + public class FrontOfficeController : ApiController + { + [AcceptVerbs("GET")] + public Catalog Catalog () + { + return CatalogManager.GetCatalog (); + } + + [AcceptVerbs("GET")] + public ProductCategory GetProductCategorie (string brandName, string prodCategorie) + { + return CatalogManager.GetCatalog ().GetBrand (brandName).GetProductCategory (prodCategorie) + ; + } + + [AcceptVerbs("POST")] + public string Command() + { + return null; + } + + + public HttpResponseMessage Post() + { + HttpResponseMessage result = null; + var httpRequest = HttpContext.Current.Request; + if (httpRequest.Files.Count > 0) + { + string username = HttpContext.Current.User.Identity.Name; + int nbf = 0; + foreach(string file in httpRequest.Files) + { + var postedFile = httpRequest.Files[file]; + string filePath = HttpContext.Current.Server.MapPath("~/users/"+username+"/"+ postedFile.FileName); + postedFile.SaveAs(filePath); + nbf++; + } + result = Request.CreateResponse (HttpStatusCode.Created, + string.Format("Received {0} files",nbf)); + + } + else + { + result = Request.CreateResponse (HttpStatusCode.BadRequest,"No file received"); + } + + return result; + } + + [HttpPost] + public string ProfileImagePost(HttpPostedFile profileImage) + { + string[] extensions = { ".jpg", ".jpeg", ".gif", ".bmp", ".png" }; + if (!extensions.Any(x => x.Equals(Path.GetExtension(profileImage.FileName.ToLower()), StringComparison.OrdinalIgnoreCase))) + { + throw new HttpResponseException( + new HttpResponseMessage(HttpStatusCode.BadRequest)); + } + + // string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads"); + // Other code goes here + // profileImage.SaveAs (); + return "/path/to/image.png"; + } + + } +} + diff --git a/web/Controllers/FrontOfficeController.cs b/web/Controllers/FrontOfficeController.cs new file mode 100644 index 00000000..c55a67de --- /dev/null +++ b/web/Controllers/FrontOfficeController.cs @@ -0,0 +1,128 @@ +using System; +using Yavsc; +using SalesCatalog; +using SalesCatalog.Model; +using System.Web.Mvc; +using System.Web; +using System.Text.RegularExpressions; +using System.IO; +using Yavsc.Controllers; +using System.Collections.Generic; + +namespace Yavsc.Controllers +{ + public class FrontOfficeController : Controller + { + [AcceptVerbs("GET")] + public ActionResult Catalog () + { + return View ( + CatalogManager.GetCatalog () + ); + } + /// + /// Catalog this instance. + /// + [AcceptVerbs("GET")] + public ActionResult Brand (string id) + { + Catalog c = CatalogManager.GetCatalog (); + ViewData ["BrandName"] = id; + return View ( c.GetBrand (id) ); + } + + /// + /// get the product category + /// + /// The category. + /// Bn. + /// Pc. + [AcceptVerbs("GET")] + public ActionResult ProductCategory (string id, string pc) + { + ViewData ["BrandName"] = id; + return View ( + CatalogManager.GetCatalog ().GetBrand (id).GetProductCategory (pc) + ); + } + + [AcceptVerbs("GET")] + public ActionResult Product (string id, string pc, string pref) + { + Product p = null; + ViewData ["BrandName"] = id; + ViewData ["ProdCatRef"] = pc; + ViewData ["ProdRef"] = pref; + Catalog cat = CatalogManager.GetCatalog (); + if (cat == null) { + ViewData ["Message"] = "Catalog introuvable"; + ViewData ["RefType"] = "Catalog"; + return View ("ReferenceNotFound"); + } + Brand b = cat.GetBrand (id); + if (b == null) { + ViewData ["RefType"] = "Brand"; + return View ("ReferenceNotFound"); + } + ProductCategory pcat = b.GetProductCategory (pc); + if (pcat == null) { + ViewData ["RefType"] = "ProductCategory"; + return View ("ReferenceNotFound"); + } + ViewData ["ProdCatName"] = pcat.Name; + p = pcat.GetProduct (pref); + if (p.CommandForm==null) + p.CommandForm = b.DefaultForm; + + return View ((p is Service)?"Service":"Product", p); + + } + + public ActionResult Command() + { + return View (); + } + + [HttpPost] + [Authorize] + public ActionResult Command(FormCollection collection) + { + try { + // get files from the request + string fnre = "[A-Za-z0-9~\\-.]+"; + HttpFileCollectionBase hfc = Request.Files; + + foreach (String h in hfc.AllKeys) + { + if (!Regex.Match(hfc[h].FileName,fnre).Success) + { + ViewData ["Message"] = "File name refused"; + ModelState.AddModelError( + h, + string.Format( + "The file name {0} dosn't match an acceptable file name {1}", + hfc[h].FileName,fnre)) + ; + return View(collection); + } + } + foreach (String h in hfc.AllKeys) + { + // TODO Limit with hfc[h].ContentLength + hfc[h].SaveAs(Path.Combine(FileSystemController.BaseDir,hfc[h].FileName)); + } + if (Session["Basket"]==null) + Session["Basket"]=new List(); + List basket = Session["Basket"] as List; + // Add specified product command to the basket, + basket.Add(new Commande(collection)); + return View (collection); + } catch (Exception e) { + ViewData ["Message"] = "Exception:"+e.Message; + return View (collection); + } + } + + } +} + diff --git a/web/Controllers/HomeController.cs b/web/Controllers/HomeController.cs new file mode 100644 index 00000000..95a15a10 --- /dev/null +++ b/web/Controllers/HomeController.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net.Mail; +using System.Web; +using System.Web.Configuration; +using System.Web.Mvc; +using System.Web.Mvc.Ajax; +using Yavsc; + +namespace Yavsc.Controllers +{ + public class HomeController : Controller + { + // Site name + private static string name = null; + + /// + /// Gets or sets the site name. + /// + /// The name. + [Obsolete("Use YavscHelpers.SiteName insteed.")] + public static string Name { + get { + if (name == null) + name = WebConfigurationManager.AppSettings ["Name"]; + return name; + } + } + // Administrator email + private static string admail = + WebConfigurationManager.AppSettings ["AdminEmail"]; + /// + /// Gets the Administrator email. + /// + /// The admail. + public static string Admail { + get { + return admail; + } + } + + + private static string owneremail = null; + /// + /// Gets or sets the owner email. + /// + /// The owner email. + public static string OwnerEmail { + get { + if (owneremail == null) + owneremail = WebConfigurationManager.AppSettings.Get ("OwnerEMail"); + return owneremail; + } + set { + owneremail = value; + } + } + + public ActionResult Index () + { + InitCatalog (); + ViewData ["Message"] = string.Format(T.GetString("Welcome")+"({0})",GetType ().Assembly.FullName); + return View (); + } + + public void InitCatalog() { + CultureInfo culture = null; + string defaultCulture = "fr"; + + if (Request.UserLanguages.Length > 0) { + try { + culture = new CultureInfo (Request.UserLanguages [0]); + } + catch (Exception e) { + ViewData ["Message"] = e.ToString (); + culture = CultureInfo.CreateSpecificCulture(defaultCulture); + } + } + else culture = CultureInfo.CreateSpecificCulture(defaultCulture); + System.Threading.Thread.CurrentThread.CurrentUICulture = culture; + System.Threading.Thread.CurrentThread.CurrentCulture = culture; + string lcd = Server.MapPath ("./locale"); + Mono.Unix.Catalog.Init("i8n1", lcd ); + } + + public ActionResult AOEMail (string reason, string body) + { + // requires valid owner and admin email? + using (System.Net.Mail.MailMessage msg = new MailMessage(owneremail,admail,"Poke : "+reason,body)) + { + using (System.Net.Mail.SmtpClient sc = new SmtpClient()) + { + sc.Send (msg); + return View (); + } + } + } + } +} diff --git a/web/Controllers/T.cs b/web/Controllers/T.cs new file mode 100644 index 00000000..a212dbad --- /dev/null +++ b/web/Controllers/T.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Configuration; +using System.Web.Mvc; +using System.Web.Mvc.Ajax; +using System.Net.Mail; +using Yavsc; +using System.Globalization; + +namespace Yavsc +{ + public class T + { + public static string GetString(string msgid) + { + return Mono.Unix.Catalog.GetString (msgid); + } + + } +} diff --git a/web/Controllers/WorkFlowController.cs b/web/Controllers/WorkFlowController.cs new file mode 100644 index 00000000..27eb9f7c --- /dev/null +++ b/web/Controllers/WorkFlowController.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +using System.Web.Http; +using WorkFlowProvider; +using yavscModel.WorkFlow; + +namespace Yavsc.ApiControllers +{ + public class WorkFlowController : ApiController + { + [HttpGet] + public object Index() + { + return new { test="Hello World" }; + } + + + public object Details(int id) + { + throw new NotImplementedException (); + } + + public object Create() + { + throw new NotImplementedException (); + } + public object Edit(int id) + { + throw new NotImplementedException (); + } + + public object Delete(int id) + { + throw new NotImplementedException (); + } + + IContentProvider contentProvider = null; + IContentProvider ContentProvider { + get { + if (contentProvider == null ) + contentProvider = WFManager.GetContentProviderFWC (); + return contentProvider; + } + } + + + } +} diff --git a/web/FileInfoCollection.cs b/web/FileInfoCollection.cs new file mode 100644 index 00000000..7212f4ed --- /dev/null +++ b/web/FileInfoCollection.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Yavsc +{ + public class FileInfoCollection : List + { + public FileInfoCollection (System.IO.FileInfo[] collection) + { + this.AddRange (collection); + } + } +} + diff --git a/web/Global.asax b/web/Global.asax new file mode 100644 index 00000000..569f561d --- /dev/null +++ b/web/Global.asax @@ -0,0 +1 @@ +<%@ Application Inherits="Yavsc.MvcApplication" %> diff --git a/web/Global.asax.cs b/web/Global.asax.cs new file mode 100644 index 00000000..bfb3ac3c --- /dev/null +++ b/web/Global.asax.cs @@ -0,0 +1,69 @@ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using System.Web.Http; + +namespace Yavsc +{ + public class MvcApplication : System.Web.HttpApplication + { + public static void RegisterRoutes (RouteCollection routes) + { + + routes.IgnoreRoute ("{resource}.axd/{*pathInfo}"); + + routes.MapRoute ( + "Blog", + "Blog/{user}/{title}", + new { controller = "Blogs", action = "Index", user=UrlParameter.Optional, title = UrlParameter.Optional } + ); + routes.MapRoute ( + "Blogs", + "Blogs/{action}/{user}/{title}", + new { controller = "Blogs", action = "Index", user=UrlParameter.Optional, title = UrlParameter.Optional} + ); + + routes.MapRoute ( + "Default", + "{controller}/{action}/{id}", + new { controller = "Home", action = "Index", id = "" } + ); + + } + + protected void Application_Start () + { + AreaRegistration.RegisterAllAreas (); + + GlobalConfiguration.Configuration.Routes.MapHttpRoute( + name: "DefaultApi", + routeTemplate: "api/{controller}/{action}/{*path}", + defaults: new { controller = "WorkFlow", action="Index", path = "" } + ); + + RegisterRoutes (RouteTable.Routes); + Error += HandleError; + } + + void HandleError (object sender, EventArgs e) + { + if (Server.GetLastError ().GetBaseException () is System.Web.HttpRequestValidationException) { + Response.Clear (); + Response.Write ("Invalid characters.
"); + Response.Write ("You may want to use your " + + "browser to go back to your form. " + + "You also can hit the url referrer."); + Response.StatusCode = 200; + Response.End (); + } + } + + } +} diff --git a/web/Helpers/BBCodeHelper.cs b/web/Helpers/BBCodeHelper.cs new file mode 100644 index 00000000..2c9246f8 --- /dev/null +++ b/web/Helpers/BBCodeHelper.cs @@ -0,0 +1,349 @@ +using System; +using CodeKicker.BBCode; +using System.Collections.Generic; +using System.Web.Mvc; +using System.Collections.Specialized; +using System.Text; + +namespace Yavsc.Helpers +{ + + public static class BBCodeHelper + { + static Dictionary parent = new Dictionary (); + private static string tclass="shoh"; + private static string cclass="hiduh"; + private static string mp4=null, ogg=null, webm=null; + public static string BBCodeViewClass { + get { + return cclass; + } + set { + cclass = value; + } + } + + public static string BBCodeCaseClass { + get { + return tclass; + } + set { + tclass = value; + } + } + + public static string[] BBTagsUsage { + get { + + List u = new List (); + foreach (BBTag t in Parser.Tags) + if (!parent.ContainsValue(t)) + { + TagBuilder tib = new TagBuilder ("div"); + tib.AddCssClass (BBCodeCaseClass); + string temp = tagUsage (t); + + tib.InnerHtml = temp; + u.Add (string.Format ("{0}
{1}
", tib.ToString (), Parser.ToHtml (temp),BBCodeViewClass)); + + + } + return u.ToArray (); + } + + + } + static string tagUsage(BBTag t,string content=null) + { + StringBuilder sb = new StringBuilder (); + sb.AppendFormat ("[{0}", t.Name); + List done = new List (); + foreach (var a in t.Attributes) { + if (string.IsNullOrEmpty (a.Name)) { + sb.AppendFormat ("=default_attribute_value"); + done.Add (a.ID); + } + } + + foreach (var a in t.Attributes) { + if (!done.Contains(a.ID)) { + sb.AppendFormat (" {0}=attribute_value", a.ID); + done.Add (a.ID); + } + } + if (content==null) + sb.AppendFormat ("]content[/{0}]", t.Name); + else + sb.AppendFormat ("]{1}[/{0}]", t.Name, content); + + if (!parent.ContainsKey(t.Name)) return sb.ToString (); + return tagUsage (parent [t.Name],sb.ToString()); + + } + private static BBCodeParser parser = null; + private static int sect1; + private static int sect2; + private static int sect3; + private static Dictionary d = new Dictionary (); + + public static void Init () + { + sect1 = 0; + sect2 = 0; + sect3 = 0; + d.Clear (); + } + + static string TocContentTransformer (string instr) + { + StringBuilder ttb = new StringBuilder (); + int m1=0, m2=0, m3=0; + foreach (string key in d.Keys) { + int s1 = 0, s2 = 0, s3 = 0; + string[] snums = key.Split ('.'); + s1 = int.Parse (snums [0]); + if (snums.Length>1) + s2 = int.Parse (snums [1]); + if (snums.Length>2) { + s3 = int.Parse (snums [2]); + } + if (m1 < s1) + m1 = s1; + if (m2 < s2) + m2 = s2; + if (m3 < s3) + m3 = s3; + + } + string[,,] toc = new string[m1+1, m2+1, m3+1]; + foreach (string key in d.Keys) { + int s1 = 0, s2 = 0, s3 = 0; + string[] snums = key.Split ('.'); + s1 = int.Parse (snums [0]); + if (snums.Length>1) + s2 = int.Parse (snums [1]); + if (snums.Length>2) { + s3 = int.Parse (snums [2]); + } + toc [s1, s2, s3] = d [key]; + } + + for (int i = 1; i<=m1; i++) { + string t1 = toc [i, 0, 0]; + // assert t1 != null + ttb.AppendFormat ("{0}) {1}
\n", i, t1); + + for (int j = 1; j <= m2; j++) { + string t2 = toc[i,j,0]; + if (t2 == null) + break; + ttb.AppendFormat ("{0}.{1}) {2}
\n", i,j, t2); + + for (int k = 1; k <= m3; k++) { + string t3 = toc[i,j,k]; + if (t3 == null) + break; + ttb.AppendFormat ("{0}.{1}.{2}) {3}
\n", i,j,k,t3); + + } + } + } + return ttb.ToString (); + } + + static string DocPageContentTransformer (string instr) + { + return TocContentTransformer(instr)+instr; + } + + static string TagContentTransformer (string instr) + { + return instr; + } + + static string TitleContentTransformer (IAttributeRenderingContext arg) + { + string tk; + if (arg.AttributeValue==null) + return null; + string t = arg.AttributeValue; + t=t.Replace ('_', ' '); + if (sect3 == 0) + if (sect2 == 0) { + tk = string.Format ("{0}", sect1); + } + else + tk = string.Format ("{0}.{1}", sect1 + 1, sect2); + else + tk = string.Format ("{0}.{1}.{2}", sect1 + 1, sect2 + 1, sect3); + if (!d.ContainsKey (tk)) + d.Add (tk, t); + return t; + } + + static string Section1Transformer (string instr) + { + sect1++; + sect2 = 0; + sect3 = 0; + return instr; + } + + static string Section2Transformer (string instr) + { + sect2++; + sect3 = 0; + return instr; + } + + static string Section3Transformer (string instr) + { + sect3++; + return instr; + } + + static string L3ContentTransformer (IAttributeRenderingContext arg) + { + return (sect1 + 1).ToString () + "." + (sect2 + 1) + "." + sect3; + } + + static string L2ContentTransformer (IAttributeRenderingContext arg) + { + return (sect1 + 1).ToString () + "." + sect2; + } + + static string L1ContentTransformer (IAttributeRenderingContext arg) + { + return sect1.ToString (); + } + static string OggSrcTr (IAttributeRenderingContext arg) + { + ogg = arg.AttributeValue; + return ogg; + } + static string Mp4SrcTr (IAttributeRenderingContext arg) + { + mp4=arg.AttributeValue; + return mp4; + } + static string WebmSrcTr (IAttributeRenderingContext arg) + { + webm = arg.AttributeValue; + return webm; + } + static string VideoContentTransformer (string cnt) + { + StringBuilder sb = new StringBuilder(); + if (mp4 != null) { + TagBuilder tb = new TagBuilder ("source"); + tb.Attributes.Add ("src", mp4); + tb.Attributes.Add ("type", "video/mp4"); + sb.Append (tb.ToString(TagRenderMode.StartTag)); + } + if (ogg != null) { + TagBuilder tb = new TagBuilder ("source"); + tb.Attributes.Add ("src", ogg); + tb.Attributes.Add ("type", "video/ogg"); + sb.Append (tb.ToString(TagRenderMode.StartTag)); + } + if (webm != null) { + TagBuilder tb = new TagBuilder ("source"); + tb.Attributes.Add ("src", webm); + tb.Attributes.Add ("type", "video/webm"); + sb.Append (tb.ToString(TagRenderMode.StartTag)); + + } + mp4 = null; + ogg=null; + webm=null; + sb.Append (cnt); + return sb.ToString(); + } + + public static BBCodeParser Parser { + get { + if (parser == null) { + Init (); + BBTag bblist =new BBTag ("list", "
    ", "
"); + BBTag bbs2=new BBTag ("sect2", + "
" + + "

${para} - ${title}

" + + "
${content}", + "
", + false, true, + Section2Transformer, + new BBAttribute ("title", "",TitleContentTransformer), + new BBAttribute ("title", "title", TitleContentTransformer), + new BBAttribute ("para", "para", L2ContentTransformer)); + BBTag bbs1=new BBTag ("sect1", + "
" + + "

${para} - ${title}

" + + "
${content}", + "
", + false, true, + Section1Transformer, + new BBAttribute ("title", "",TitleContentTransformer), + new BBAttribute ("title", "title", TitleContentTransformer), + new BBAttribute ("para", "para", L1ContentTransformer)); + BBTag bbdp=new BBTag ("docpage", + "
${content}
", "", + false, + false, + DocPageContentTransformer); + + parser = new BBCodeParser (new[] { + new BBTag ("b", "", ""), + new BBTag ("i", "", ""), + new BBTag ("u", "", ""), + new BBTag ("code", "", ""), + new BBTag ("img", "", "", false, true, new BBAttribute ("style", "style")), + new BBTag ("quote", "
", "
"), + new BBTag ("div", "
", "
", new BBAttribute("style","style")), + new BBTag ("p", "

", "

"), + new BBTag ("h", "

", "

"), + bblist, + new BBTag ("*", "
  • ", "
  • ", true, false), + new BBTag ("url", "", "", new BBAttribute ("href", ""), new BBAttribute ("href", "href")), + new BBTag ("br", "
    ", "", true, false), + new BBTag ("video", "", + new BBAttribute("mp4","mp4"), + new BBAttribute("ogg","ogg"), + new BBAttribute("webm","webm"), + new BBAttribute("style","style")), + new BBTag ("tag", "", "", true, true, + TagContentTransformer), + bbs1, + bbs2, + new BBTag ("sect3", + "
    " + + "

    ${para} - ${title}

    " + + "
    ${content}", + "
    ", + false, true, + Section3Transformer, + new BBAttribute ("title", "",TitleContentTransformer), + new BBAttribute ("title", "title", TitleContentTransformer), + new BBAttribute ("para", "para", L3ContentTransformer) + ), + bbdp, + new BBTag ("f", "", + new BBAttribute ("src", ""), new BBAttribute ("src", "src")), + + } + ); + parent.Add ("*", bblist); + parent.Add ("sect3", bbs2); + parent.Add ("sect2", bbs1); + parent.Add ("sect1", bbdp); + + } + return parser; + } + + } + } +} + diff --git a/web/Helpers/YavscHelpers.cs b/web/Helpers/YavscHelpers.cs new file mode 100644 index 00000000..2c3ef918 --- /dev/null +++ b/web/Helpers/YavscHelpers.cs @@ -0,0 +1,19 @@ +using System; +using System.Web; +using System.Configuration; + +namespace Yavsc.Helpers +{ + public static class YavscHelpers + { + private static string siteName = null; + public static string SiteName { + get { + if (siteName == null) + siteName = ConfigurationManager.AppSettings ["Name"]; + return siteName; + } + } + } +} + diff --git a/web/Models/App.master b/web/Models/App.master new file mode 100644 index 00000000..0ae55003 --- /dev/null +++ b/web/Models/App.master @@ -0,0 +1,61 @@ +<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> + + + + + + + + + + <asp:ContentPlaceHolder ID="titleContent" runat="server" /> + <asp:Literal runat="server" Text=" - " /><%= YavscHelpers.SiteName %> + + + + +
    +
    + <% if (Membership.GetUser()==null) { %> + +<%= Html.ActionLink("Login", "Login", "Account", new { returnUrl=Request.Url.PathAndQuery }, null ) %> + +<% } else { %> +<%= HttpContext.Current.User.Identity.Name %> + +<%= Html.ActionLink( "Logout", "Logout", "Account", new { returnUrl=Request.Url.PathAndQuery }, null) %> + <%= Html.ActionLink( "Poster", "Post", "Blogs" ) %> + <%= Html.ActionLink( "Profile", "Profile", "Account" ) %> + +<% } %> + <%= Html.ActionLink( "Accueil", "Index", "Home" ) %> + +
    + + + +

    <%=Html.Encode(YavscHelpers.SiteName)%>

    +<% if (ViewData["Error"]!=null) { %> +
    +<%= Html.Encode(ViewData["Error"]) %> +
    +<% } %> +<% if (ViewData["Message"]!=null) { %> +
    +<%= Html.Encode(ViewData["Message"]) %> +
    +<% } %> +
    +
    +
    + + + +
    +
    +
    + <%= string.Join("\n",Yavsc.ThanksHelper.Links()) %> +
    + + + diff --git a/web/README b/web/README new file mode 100644 index 00000000..c999c3dd --- /dev/null +++ b/web/README @@ -0,0 +1,45 @@ + Yavsc is a point of sales, implemented in a dot Net Web application + Copyright (C) 2014 Paul Schneider + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +You may contact me at + +------- + +Yavsc ("Mon Auto Entreprise") + +Les services : + +- Dépannage informatique +- Développement logiciel +- Developpement Web +- Audit de sécurité +- Dématérialisation des documents +- ... + +Les livrables : + +- Un site web ASP.Net propulsé par Mono et Apache, et une application mobile pour + * demander un devis + * avoir un status des projets des clients + * demander une intervention / saisir un ticket + * avoir un status des ticket du client + +Les projets : + +- des acteurs / des ressources humaines +- des etapes inter dépendantes, leurs attributs, leurs états +- des dates butoires + diff --git a/web/RegistrationMail.txt b/web/RegistrationMail.txt new file mode 100644 index 00000000..90e5bec0 --- /dev/null +++ b/web/RegistrationMail.txt @@ -0,0 +1,9 @@ + +Votre compte <%SiteName%> a été créé, votre nom d'utilisateur +est <%UserName%>. + +Pour l'activer, veuillez suivre le lien suivant : + +<%UserActivatonUrl%> + +Merci d'avoir créé un compte utilisateur. diff --git a/web/Test/TestByteA.cs b/web/Test/TestByteA.cs new file mode 100644 index 00000000..bad66d98 --- /dev/null +++ b/web/Test/TestByteA.cs @@ -0,0 +1,87 @@ +using NUnit.Framework; +using System; +using System.Configuration; +using Npgsql; + +namespace Yavsc +{ + [TestFixture ()] + public class TestByteA: IDisposable + { + //string cnxName = "yavsc"; + string ConnectionString { get { + return "Server=127.0.0.1;Port=5432;Database=mae;User Id=mae;Password=admin;Encoding=Unicode;" ; + // return ConfigurationManager.ConnectionStrings [cnxName].ConnectionString; + + } } + + [TestFixtureSetUp] + public void Init() + { + // create the table + Console.WriteLine ("cnx:"+ConnectionString); + using (NpgsqlConnection cnx = new NpgsqlConnection (ConnectionString)) + { + cnx.Open (); + using (NpgsqlCommand cmd = cnx.CreateCommand ()) { + cmd.CommandText = "drop table testbytea"; + try { cmd.ExecuteNonQuery (); } + catch (NpgsqlException) { + } + cmd.CommandText = "create table testbytea( t bytea )"; + cmd.ExecuteNonQuery (); + } + } + } + + [Test(Description="Test storing a byte array in a Postgresql table field")] + public void TestStoreByteA () + { + byte []a = new byte[3]; + a[0]=1; + a[1]=2; + a[2]=3; + using (NpgsqlConnection cnx = new NpgsqlConnection (ConnectionString)) { + cnx.Open (); + using (NpgsqlCommand cmd = cnx.CreateCommand ()) + { + cmd.CommandText = "insert into testbytea (t) values (@tv)"; + cmd.Parameters.Add ("@tv", a); + cmd.ExecuteNonQuery (); + } + + using (NpgsqlCommand cmd = cnx.CreateCommand ()) + { + cmd.CommandText = "select t from testbytea"; + cmd.Parameters.Add ("@tv", a); + + NpgsqlDataReader rdr = cmd.ExecuteReader (); + if (!rdr.Read ()) + throw new Exception ("Read failed"); + int i = rdr.GetOrdinal ("t"); + byte []rded = (byte[]) rdr.GetValue (i); + if (rded.Length!=a.Length) + throw new Exception("Lengthes don't match"); + } + } + } + + #region IDisposable implementation + + [TestFixtureTearDown] + public void Dispose () + { + // drop the table + using (NpgsqlConnection cnx = new NpgsqlConnection (ConnectionString)) { + cnx.Open (); + using (NpgsqlCommand cmd = cnx.CreateCommand ()) { + cmd.CommandText = "drop table testbytea"; + cmd.ExecuteNonQuery (); + } + } + } + + #endregion + } +} + diff --git a/web/Tests.cs b/web/Tests.cs new file mode 100644 index 00000000..975f22a3 --- /dev/null +++ b/web/Tests.cs @@ -0,0 +1,19 @@ + +#if TEST + +using System; +using NUnit.Framework; + +namespace Yavsc +{ + [TestFixture()] + public class Tests + { + [Test()] + public void TestCase () + { + } + } +} + +#endif diff --git a/web/TextWriterOutput.log b/web/TextWriterOutput.log new file mode 100644 index 00000000..e69de29b diff --git a/web/Thanks/ThanksConfigurationCollection.cs b/web/Thanks/ThanksConfigurationCollection.cs new file mode 100644 index 00000000..d97460a7 --- /dev/null +++ b/web/Thanks/ThanksConfigurationCollection.cs @@ -0,0 +1,22 @@ +using System; +using System.Configuration; + +namespace Yavsc +{ + public class ThanksConfigurationCollection : ConfigurationElementCollection + { + protected override object GetElementKey (ConfigurationElement element) + { + return ((ThanksConfigurationElement) element).Name; + } + protected override ConfigurationElement CreateNewElement () + { + return new ThanksConfigurationElement(); + } + public ThanksConfigurationElement GetElement (string name) + { + return this.BaseGet(name) as ThanksConfigurationElement; + } + } +} + diff --git a/web/Thanks/ThanksConfigurationElement.cs b/web/Thanks/ThanksConfigurationElement.cs new file mode 100644 index 00000000..a4b71f14 --- /dev/null +++ b/web/Thanks/ThanksConfigurationElement.cs @@ -0,0 +1,48 @@ +using System; +using System.Configuration; + +namespace Yavsc +{ + public class ThanksConfigurationElement : ConfigurationElement + { + [ConfigurationProperty("name", IsKey=true, IsRequired=true)] + public string Name { + get { + return (string) base ["name"]; + } + set { base ["name"] = value; } + } + + [ConfigurationProperty("url")] + public string Url { + get { + return (string) base ["url"]; + } + set { base ["url"] = value; } + } + + [ConfigurationProperty("image")] + public string Image { + get { + return (string) base ["image"]; + } + set { base ["image"] = value; } + } + + /// + /// Gets or sets the display. + /// + /// + /// The displaied text when no image is provided and we + /// don't want use the name attribute. + /// + [ConfigurationProperty("display")] + public string Display { + get { + return (string) base ["display"]; + } + set { base ["display"] = value; } + } + } +} + diff --git a/web/Thanks/ThanksConfigurationSection.cs b/web/Thanks/ThanksConfigurationSection.cs new file mode 100644 index 00000000..c86382ea --- /dev/null +++ b/web/Thanks/ThanksConfigurationSection.cs @@ -0,0 +1,39 @@ +using System; +using System.Configuration; + +namespace Yavsc +{ + public class ThanksConfigurationSection : ConfigurationSection + { + [ConfigurationProperty("to")] + public ThanksConfigurationCollection To { + get { + return (ThanksConfigurationCollection) this["to"]; + } + set { + this ["to"] = value; + } + } + + [ConfigurationProperty("html_class")] + public string HtmlClass { + get { + return (string)this ["html_class"]; + } + set { + this ["html_class"] = value; + } + } + + [ConfigurationProperty("title_format")] + public string TitleFormat { + get { + return (string)this ["title_format"]; + } + set { + this ["title_format"] = value; + } + } + } +} + diff --git a/web/Thanks/ThanksHelper.cs b/web/Thanks/ThanksHelper.cs new file mode 100644 index 00000000..3f5bbf72 --- /dev/null +++ b/web/Thanks/ThanksHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.Configuration; +using System.Collections.Generic; + +namespace Yavsc +{ + public static class ThanksHelper { + + public static string[] Links () + { + List result = new List() ; + ThanksConfigurationSection s = (ThanksConfigurationSection) ConfigurationManager.GetSection ("system.web/thanks"); + if (s == null) return result.ToArray(); + if (s.To == null) return result.ToArray(); + foreach (ThanksConfigurationElement e in s.To) { + string link = ""; + if (!string.IsNullOrEmpty(e.Url)) + link = string.Format("",e.Url); + link += "
    "; + string dsp = (string.IsNullOrEmpty(e.Display))?e.Name:e.Display; + if (!string.IsNullOrEmpty(e.Image)) { + string ttl = (string.IsNullOrEmpty(s.TitleFormat))?"Go and see the website ({0})":s.TitleFormat; + ttl = string.Format(ttl,dsp); + link += string.Format( + "\"{0}\"", + dsp,e.Image,ttl); + } + else link += dsp; + link += "
    "; + if (e.Url!=null) + link += "
    "; + result.Add (link); + } + return result.ToArray(); + } + } + +} diff --git a/web/Views/Account/AddRole.aspx b/web/Views/Account/AddRole.aspx new file mode 100644 index 00000000..d0ba38b5 --- /dev/null +++ b/web/Views/Account/AddRole.aspx @@ -0,0 +1,19 @@ +<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Ajout d'un role

    +
    + + +<%= Html.ValidationSummary() %> +<% using(Html.BeginForm("DoAddRole", "Account")) %> +<% { %> +Nom du rôle : +<%= Html.TextBox( "RoleName" ) %> +<%= Html.ValidationMessage("RoleName", "*") %>
    + +<% } %> +
    + + diff --git a/web/Views/Account/Admin.aspx b/web/Views/Account/Admin.aspx new file mode 100644 index 00000000..65e9df7c --- /dev/null +++ b/web/Views/Account/Admin.aspx @@ -0,0 +1,34 @@ +<%@ Page Title="Administration" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + +

    Liste des administrateurs

    +
    + + +
    + + +<% foreach (string u in (string[])ViewData["admins"]) { %> + + +<% } %> +
    +<%= u %> <%= Html.ActionLink("Remove","RemoveFromRole",new { username = u, rolename="Admin", returnUrl = Request.Url.PathAndQuery })%> +
    +
    +
    +

    Ajout d'un administrateur +

    +

    <%= Html.ValidationSummary() %>

    + +<% using ( Html.BeginForm("Admin", "Account") ) { %> + +<%= Html.LabelFor(model => model.UserName) %> : +<%= Html.DropDownListFor(model => model.UserName, (List)ViewData["useritems"] ) %> +<%= Html.ValidationMessage("UserName", "*") %> + + + <% } %> + +
    +
    + diff --git a/web/Views/Account/ChangePassword.aspx b/web/Views/Account/ChangePassword.aspx new file mode 100644 index 00000000..d272736c --- /dev/null +++ b/web/Views/Account/ChangePassword.aspx @@ -0,0 +1,26 @@ +<%@ Page Title="Change your Password" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + + + +<%= Html.ValidationSummary("Modification de mot de passe") %> +<% using(Html.BeginForm("ChangePassword", "Account")) { %> + +<%= Html.TextBox( "UserName" ) %> +<%= Html.ValidationMessage("UserName", "*") %>
    + + <%= Html.Password( "OldPassword" ) %> +<%= Html.ValidationMessage("OldPassword", "*") %>
    + + <%= Html.Password( "NewPassword" ) %> +<%= Html.ValidationMessage("NewPassword", "*") %>
    + + <%= Html.Password( "ConfirmPassword" ) %> +<%= Html.ValidationMessage("ConfirmPassword", "*") %> + +<% } %> + +
    + + diff --git a/web/Views/Account/ChangePasswordSuccess.aspx b/web/Views/Account/ChangePasswordSuccess.aspx new file mode 100644 index 00000000..1a3bf654 --- /dev/null +++ b/web/Views/Account/ChangePasswordSuccess.aspx @@ -0,0 +1,8 @@ +<%@ Page Title="Successfully changed your password" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +
    +<%= Html.ActionLink("Register","Register")%>
    +
    <%= Html.ActionLink("ChangePassword","ChangePassword")%>
    +
    diff --git a/web/Views/Account/Index.aspx b/web/Views/Account/Index.aspx new file mode 100644 index 00000000..a75eb950 --- /dev/null +++ b/web/Views/Account/Index.aspx @@ -0,0 +1,8 @@ +<%@ Page Title="Comptes utilisateur - Index" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Comptes utilisteur

    +
    + + diff --git a/web/Views/Account/Login.aspx b/web/Views/Account/Login.aspx new file mode 100644 index 00000000..a96ea09f --- /dev/null +++ b/web/Views/Account/Login.aspx @@ -0,0 +1,28 @@ +<%@ Page Title="Login" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + + +
    +<%= Html.ValidationSummary("Ouverture de session") %> +<% using(Html.BeginForm("DoLogin", "Account")) %> +<% { %> +<%= Html.LabelFor(model => model.UserName) %> +<%= Html.TextBox( "UserName" ) %> +<%= Html.ValidationMessage("UserName", "*") %>
    + +<%= Html.LabelFor(model => model.Password) %> +<%= Html.Password( "Password" ) %> +<%= Html.ValidationMessage("Password", "*") %>
    + + +<%= Html.CheckBox("RememberMe") %> +<%= Html.ValidationMessage("RememberMe", "") %>
    +<%= Html.Hidden("returnUrl",ViewData["returnUrl"]) %> + + +<% } %> +
    +
    +<%= Html.ActionLink("S'enregistrer","Register",new {returnUrl=ViewData["returnUrl"]}) %>
    +
    diff --git a/web/Views/Account/Profile.aspx b/web/Views/Account/Profile.aspx new file mode 100644 index 00000000..113dde26 --- /dev/null +++ b/web/Views/Account/Profile.aspx @@ -0,0 +1,47 @@ +<%@ Page Title="Profile" Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + +<%=ViewData["UserName"]%> : Profile - <%=YavscHelpers.SiteName%> + + +

    <%=ViewData["UserName"]%> : Profile - <%=YavscHelpers.SiteName%>

    +

    <%= Html.ActionLink("Changer de mot de passe","ChangePassword", "Account")%>

    +
    + +<%= Html.ValidationSummary() %> +<% using(Html.BeginForm("UpdateProfile", "Account", FormMethod.Post, new { enctype = "multipart/form-data" })) %> +<% { %> + + + + + + + + + + +
    +<%= Html.LabelFor(model => model.Address) %> +<%= Html.TextBox("Address") %> +<%= Html.ValidationMessage("Address", "*") %>
    +<%= Html.LabelFor(model => model.CityAndState) %> +<%= Html.TextBox("CityAndState") %> +<%= Html.ValidationMessage("CityAndState", "*") %>
    +<%= Html.LabelFor(model => model.Country) %> +<%= Html.TextBox("Country") %> +<%= Html.ValidationMessage("Country", "*") %>
    +<%= Html.LabelFor(model => model.WebSite) %> +<%= Html.TextBox("WebSite") %> +<%= Html.ValidationMessage("WebSite", "*") %>
    +<%= Html.LabelFor(model => model.BlogVisible) %> +<%= Html.CheckBox("BlogVisible") %> +<%= Html.ValidationMessage("BlogVisible", "*") %>
    +<%= Html.LabelFor(model => model.BlogTitle) %> +<%= Html.TextBox("BlogTitle") %> +<%= Html.ValidationMessage("BlogTitle", "*") %>
    +Avatar " alt=""/> + +<%= Html.ValidationMessage("AvatarFile", "*") %>
    + +<% } %> +
    diff --git a/web/Views/Account/Register.aspx b/web/Views/Account/Register.aspx new file mode 100644 index 00000000..b501dddf --- /dev/null +++ b/web/Views/Account/Register.aspx @@ -0,0 +1,45 @@ +<%@ Page Title="Register" Language="C#" Inherits="Yavsc.RegisterPage" MasterPageFile="~/Models/App.master" %> + + + + +

    Créez votre compte utilisateur <%= Html.Encode(YavscHelpers.SiteName) %>

    +
    + + +<%= Html.ValidationSummary() %> +<% using(Html.BeginForm("Register", "Account")) %> +<% { %> + + + + + +
    +<%= Html.LabelFor(model => model.UserName) %> + +<%= Html.TextBox( "UserName" ) %> +<%= Html.ValidationMessage("UserName", "*") %>
    +<%= Html.LabelFor(model => model.Password) %> + +<%= Html.Password( "Password" ) %> +<%= Html.ValidationMessage("Password", "*") %> +
    +<%= Html.LabelFor(model => model.ConfirmPassword) %> + + <%= Html.Password( "ConfirmPassword" ) %> +<%= Html.ValidationMessage("ConfirmPassword", "*") %> +
    +<%= Html.LabelFor(model => model.Email) %> + +<%= Html.TextBox( "Email" ) %> +<%= Html.ValidationMessage("Email", "*") %> +
    +
    +<%= Html.Hidden("returnUrl",ViewData["returnUrl"]) %> + + +<% } %> +
    + + diff --git a/web/Views/Account/RegistrationPending.aspx b/web/Views/Account/RegistrationPending.aspx new file mode 100644 index 00000000..7bb96ab4 --- /dev/null +++ b/web/Views/Account/RegistrationPending.aspx @@ -0,0 +1,17 @@ +<%@ Page Title="Comptes utilisateur - Index" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Comptes utilisteur

    +
    + +

    +Votre compte utilisateur +<%= Html.Encode(YavscHelpers.SiteName) %> +a été créé, un e-mail de validation de votre compte a été envoyé a l'adresse fournie:
    +<<%= Html.Encode(ViewData["email"]) %>>.
    +Vous devriez le recevoir rapidement.
    +Pour valider votre compte, suivez le lien indiqué dans cet e-mail. +

    +">Retour +
    diff --git a/web/Views/Account/RemoveRoleQuery.aspx b/web/Views/Account/RemoveRoleQuery.aspx new file mode 100644 index 00000000..a6bc14b4 --- /dev/null +++ b/web/Views/Account/RemoveRoleQuery.aspx @@ -0,0 +1,22 @@ +<%@ Page Title="User removal" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Suppression d'un rôle

    +
    + +
    +<%= Html.ValidationSummary() %> +<% using ( Html.BeginForm("RemoveRole") ) { %> +Supprimer le rôle +<%= Html.Encode( ViewData["roletoremove"] ) %> ? +
    +"/> + + +<% } %> +
    + +
    + + diff --git a/web/Views/Account/RemoveUserQuery.aspx b/web/Views/Account/RemoveUserQuery.aspx new file mode 100644 index 00000000..8e5fd740 --- /dev/null +++ b/web/Views/Account/RemoveUserQuery.aspx @@ -0,0 +1,22 @@ +<%@ Page Title="User removal" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Suppression d'un utilisateur

    +
    + +
    +<%= Html.ValidationSummary() %> +<% using ( Html.BeginForm("RemoveUser","Account") ) { %> +Supprimer l'utilisateur +<%= Html.Encode( ViewData["usertoremove"] ) %> ? +
    +"/> + + +<% } %> +
    + +
    + + diff --git a/web/Views/Account/RoleList.aspx b/web/Views/Account/RoleList.aspx new file mode 100644 index 00000000..573fb065 --- /dev/null +++ b/web/Views/Account/RoleList.aspx @@ -0,0 +1,23 @@ +<%@ Page Title="Role list" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Liste des rôles

    +
    + +Roles: +
      + <%foreach (string rolename in (string[]) Model){ %> + +
    • <%=rolename%> <% if (Roles.IsUserInRole("Admin")) { %> + <%= Html.ActionLink("Supprimer","RemoveRole", new { rolename = rolename }, new { @class="actionlink" } ) %> +<% } %>
    • + <% } %> + +
    + <% if (Roles.IsUserInRole("Admin")) { %> + <%= Html.ActionLink("Ajouter un rôle","AddRole", null, new { @class="actionlink" } ) %> +<% } %> +
    + + diff --git a/web/Views/Account/UserList.aspx b/web/Views/Account/UserList.aspx new file mode 100644 index 00000000..b506bd92 --- /dev/null +++ b/web/Views/Account/UserList.aspx @@ -0,0 +1,22 @@ +<%@ Page Title="User List" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Liste des utilisateurs

    +
    + + +
      + <%foreach (MembershipUser user in Model){ %> + +
    • <%=user.UserName%> <%=user.Email%> <%=(!user.IsApproved)?"(Not Approuved)":""%> <%=user.IsOnline?"Online":"Offline"%> +<% if (Roles.IsUserInRole("Admin")) { %> + <%= Html.ActionLink("Supprimer","RemoveUserQuery", new { username = user.UserName }, new { @class="actionlink" } ) %> +<% } %> +
    • + + <% }%> +
    + +
    + diff --git a/web/Views/Account/Validate.aspx b/web/Views/Account/Validate.aspx new file mode 100644 index 00000000..a26c70d5 --- /dev/null +++ b/web/Views/Account/Validate.aspx @@ -0,0 +1,8 @@ +<%@ Page Title="Comptes utilisateur - Validation" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Validation d'un compte utilisateur

    +
    + + diff --git a/web/Views/BackOffice/BackupCreated.aspx b/web/Views/BackOffice/BackupCreated.aspx new file mode 100644 index 00000000..a965d9d5 --- /dev/null +++ b/web/Views/BackOffice/BackupCreated.aspx @@ -0,0 +1,13 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + +

    Backup created

    +
    + +

    Error message

    <%= Html.Encode(Model.Error) %>
    +

    Message

    <%= Html.Encode(Model.Message) %>
    +

    File name

    <%= Html.Encode(Model.FileName) %>
    +

    Exit Code

    <%= Html.Encode(Model.ExitCode) %>
    + +
    diff --git a/web/Views/BackOffice/Backups.aspx b/web/Views/BackOffice/Backups.aspx new file mode 100644 index 00000000..5f625d33 --- /dev/null +++ b/web/Views/BackOffice/Backups.aspx @@ -0,0 +1,12 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + +Backups + + +

    Backups

    +
    + + +<%=Html.ActionLink("Create a database backup", "CreateBackup", "BackOffice")%>
    +<%=Html.ActionLink("Restaurations", "Restore", "BackOffice")%>
    +
    diff --git a/web/Views/BackOffice/CreateBackup.aspx b/web/Views/BackOffice/CreateBackup.aspx new file mode 100644 index 00000000..c287ffe7 --- /dev/null +++ b/web/Views/BackOffice/CreateBackup.aspx @@ -0,0 +1,27 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + +<%= Html.ValidationSummary("CreateBackup") %> +<% using (Html.BeginForm("CreateBackup","BackOffice")) { %> + +<%= Html.LabelFor(model => model.Host) %>: +<%= Html.TextBox( "Host" ) %> +<%= Html.ValidationMessage("Host", "*") %>
    +<%= Html.LabelFor(model => model.Port) %>: +<%= Html.TextBox( "Port" ) %> +<%= Html.ValidationMessage("Port", "*") %>
    +<%= Html.LabelFor(model => model.Dbname) %>: +<%= Html.TextBox( "Dbname" ) %> +<%= Html.ValidationMessage("Dbname", "*") %>
    +<%= Html.LabelFor(model => model.Dbuser) %>: +<%= Html.TextBox( "Dbuser" ) %> +<%= Html.ValidationMessage("Dbuser", "*") %>
    +<%= Html.LabelFor(model => model.Password) %>: +<%= Html.Password( "Password" ) %> +<%= Html.ValidationMessage("Password", "*") %>
    + +<% } %> +
    diff --git a/web/Views/BackOffice/Index.aspx b/web/Views/BackOffice/Index.aspx new file mode 100644 index 00000000..0a999001 --- /dev/null +++ b/web/Views/BackOffice/Index.aspx @@ -0,0 +1,8 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + +<%= Html.ActionLink("Backups","Backups","BackOffice") %> + diff --git a/web/Views/BackOffice/Restore.aspx b/web/Views/BackOffice/Restore.aspx new file mode 100644 index 00000000..523e2b77 --- /dev/null +++ b/web/Views/BackOffice/Restore.aspx @@ -0,0 +1,43 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + + +<%= Html.ValidationSummary("Restore a database backup") %> +<% using (Html.BeginForm("Restore","BackOffice")) { %> + +<% string [] bckdirs = Model.GetBackupDirs(); %> + + +<%= Html.CheckBox("dataOnly")%> + +<%= Html.LabelFor(model => model.Host) %>: +<%= Html.TextBox( "Host" ) %> +<%= Html.ValidationMessage("Host", "*") %>
    +<%= Html.LabelFor(model => model.Port) %>: +<%= Html.TextBox( "Port" ) %> +<%= Html.ValidationMessage("Port", "*") %>
    +<%= Html.LabelFor(model => model.Dbname) %>: +<%= Html.TextBox( "Dbname" ) %> +<%= Html.ValidationMessage("Dbname", "*") %>
    +<%= Html.LabelFor(model => model.Dbuser) %>: +<%= Html.TextBox( "Dbuser" ) %> +<%= Html.ValidationMessage("Dbuser", "*") %>
    +<%= Html.LabelFor(model => model.Password) %>: +<%= Html.Password( "Password" ) %> +<%= Html.ValidationMessage("Password", "*") %>
    + + +<% } %> +
    diff --git a/web/Views/BackOffice/Restored.aspx b/web/Views/BackOffice/Restored.aspx new file mode 100644 index 00000000..cb320315 --- /dev/null +++ b/web/Views/BackOffice/Restored.aspx @@ -0,0 +1,12 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + +

    <%=Html.Encode(ViewData["BackupName"])%> Restauration

    +

    Error message

    <%= Html.Encode(Model.Error) %>
    +

    Message

    <%= Html.Encode(Model.Message) %>
    +

    Exit Code

    <%= Html.Encode(Model.ExitCode) %>
    + +
    diff --git a/web/Views/Blogs/Edit.aspx b/web/Views/Blogs/Edit.aspx new file mode 100644 index 00000000..da110bf5 --- /dev/null +++ b/web/Views/Blogs/Edit.aspx @@ -0,0 +1,67 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> + + <%= Html.Encode(ViewData["BlogTitle"]) %> edition + - <%=Html.Encode(YavscHelpers.SiteName) %> + + + + +

    + "> + " alt="from <%=ViewData["UserName"]%>"/> + <%= Html.Encode(ViewData["BlogTitle"]) %> - + <%= Html.Encode(Model.Title) %> - + Édition

    + + + +
    + <%= Html.Encode(ViewData["Message"]) %> +
    +
    + + + +<% if (Model != null ) if (Model.Content != null ) { + BBCodeHelper.Init (); %> + <%= Html.ActionLink(Model.Title,"UserPost",new{user=Model.UserName,title=Model.Title}) %> +
    +<%= BBCodeHelper.Parser.ToHtml(Model.Content) %> +
    +<% } %> +Usage BBcodes : +
    +<% + foreach (string usage in BBCodeHelper.BBTagsUsage) { %> +
    <%= usage %>
    +<% } %> +
    + +<%= Html.ValidationSummary("Edition du billet") %> + +<% using(Html.BeginForm("ValidateEdit", "Blogs")) { %> +<%= Html.LabelFor(model => model.Title) %>:
    +<%= Html.TextBox( "Title" ) %> +<%= Html.ValidationMessage("Title", "*") %> +
    +<%= Html.LabelFor(model => model.Content) %>:
    +<%= Html.TextArea( "Content" , new { @class="editblog", @rows="15" }) %> +<%= Html.ValidationMessage("Content", "*") %> +
    +<%= Html.CheckBox( "Visible" ) %> +<%= Html.LabelFor(model => model.Visible) %> +<%= Html.ValidationMessage("Visible", "*") %> +
    +<%= Html.CheckBox( "Preview" ) %> +<%= Html.LabelFor(model => model.Preview) %> +<%= Html.ValidationMessage("Preview", "*") %> + <%= Html.Hidden("Id") %> + <%= Html.Hidden("UserName") %> + +
    + +<% } %> + + +
    + diff --git a/web/Views/Blogs/Error.aspx b/web/Views/Blogs/Error.aspx new file mode 100644 index 00000000..e49602ac --- /dev/null +++ b/web/Views/Blogs/Error.aspx @@ -0,0 +1,14 @@ +<%@ Page Title="Comptes utilisateur - Index" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    Comptes utilisteur

    +
    + + +
    +<%= Html.Encode(ViewData["Message"]) %>
    +Your UID : +<%= Html.Encode(ViewData ["UID"]) %>
    +">Retour +
    diff --git a/web/Views/Blogs/Index.aspx b/web/Views/Blogs/Index.aspx new file mode 100644 index 00000000..9f262830 --- /dev/null +++ b/web/Views/Blogs/Index.aspx @@ -0,0 +1,34 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> +<%@ Register Assembly="Yavsc.WebControls" TagPrefix="yavsc" Namespace="Yavsc.WebControls" %> + + <%= "Les dernières parutions - " + Html.Encode(YavscHelpers.SiteName) + "" %> + + +

    Les dernières parutions

    +
    + + +<% foreach (Npgsql.Web.Blog.DataModel.BlogEntry e in this.Model) { %> +
    +

    +<%= Html.ActionLink(e.Title,"UserPost", new { user=e.UserName, title = e.Title }) %> +

    +
    (<%=Html.Encode(e.UserName)%> <%=e.Modified.ToString("yyyy/MM/dd") %>)
    +<% if (Membership.GetUser()!=null) + if (Membership.GetUser().UserName==e.UserName) + { %> + <%= Html.ActionLink("Editer","Edit", new { user = e.UserName, title = e.Title }, new { @class="actionlink" }) %> + <%= Html.ActionLink("Supprimer","Remove", new { user = e.UserName, title = e.Title }, new { @class="actionlink" } ) %> + <% } %> + +
    + +<% } %> +
    + <% rp1.ResultCount = (int) ViewData["RecordCount"]; + rp1.CurrentPage = (int) ViewData["PageIndex"]; %> + + +
    +
    + diff --git a/web/Views/Blogs/Post.aspx b/web/Views/Blogs/Post.aspx new file mode 100644 index 00000000..b8cd1e39 --- /dev/null +++ b/web/Views/Blogs/Post.aspx @@ -0,0 +1,67 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> + + <%= Html.Encode(ViewData["BlogTitle"]) %> - Nouveau billet + - <%=Html.Encode(YavscHelpers.SiteName) %> + + + +

    + "> + " alt="from <%=ViewData["UserName"]%>"/> + <%= Html.Encode(ViewData["BlogTitle"]) %> - +Nouveau billet - +<%= Html.Encode(YavscHelpers.SiteName) %>

    + +
    + <%= Html.Encode(ViewData["Message"]) %> +
    +
    + + +
    + <%= Html.Encode(ViewData["Message"]) %> +
    + <% if (Model != null ) if (Model.Content != null ) { %> +
    +<%= BBCodeHelper.Parser.ToHtml(Model.Content) %> +
    +<% } %> +
    + + +<%= Html.ValidationSummary() %> +<% using(Html.BeginForm("ValidatePost", "Blogs")) %> +<% { %> + +<%= Html.LabelFor(model => model.Title) %>:
    +<%= Html.TextBox( "Title" ) %> +<%= Html.ValidationMessage("Title", "*") %> +
    +
    + Usage BBcodes : +
      +<% + foreach (string usage in BBCodeHelper.BBTagsUsage) { %> +
    • <%= usage %>
    • +<% } %> +
    + +
    +<%= Html.LabelFor(model => model.Content) %>:
    +<%= Html.TextArea( "Content", new { @class="editblog", @rows="15" }) %> +<%= Html.ValidationMessage("Content", "*") %> +
    +<%= Html.CheckBox( "Visible" ) %> +<%= Html.LabelFor(model => model.Visible) %> +<%= Html.ValidationMessage("Visible", "*") %> +
    +<%= Html.CheckBox( "Preview" ) %> <%= Html.LabelFor(model => model.Preview) %> +<%= Html.ValidationMessage("Preview", "*") %> +
    + <%= Html.Hidden("Id") %> + +<% } %> + +
    +
    + diff --git a/web/Views/Blogs/TitleNotFound.aspx b/web/Views/Blogs/TitleNotFound.aspx new file mode 100644 index 00000000..4aa369a4 --- /dev/null +++ b/web/Views/Blogs/TitleNotFound.aspx @@ -0,0 +1,17 @@ + +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> + + + + + + + + Pas d'article trouvé @ "<%= Html.Encode(ViewData["PostTitle"]) %>" + <% if (ViewData["UserName"]!=null) { %> + +
    + <%= Html.ActionLink("Poster?","Post/", new { user=ViewData["UserName"], title = ViewData["PostTitle"]}, new { @class="actionlink" }) %> + <% } %> +
    + diff --git a/web/Views/Blogs/UserPost.aspx b/web/Views/Blogs/UserPost.aspx new file mode 100644 index 00000000..f8b4a188 --- /dev/null +++ b/web/Views/Blogs/UserPost.aspx @@ -0,0 +1,47 @@ +<%@ Page Title="Billet" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> +<%=Html.Encode(Model.Title)%> - <%=Html.Encode(ViewData["BlogTitle"])%> + +

    <%= Html.ActionLink(Model.Title,"UserPost",new{user=Model.UserName,title=Model.Title}) %> - + <%=ViewData["BlogTitle"]%>

    + +
    (Id:<%=Model.Id%>, <%= Model.Posted.ToString("yyyy/MM/dd") %> + - <%= Model.Modified.ToString("yyyy/MM/dd") %> <%= Model.Visible? "":", Invisible!" %>) +<% if (Membership.GetUser()!=null) + if (Membership.GetUser().UserName==Model.UserName) + { %> + <%= Html.ActionLink("Editer","Edit", new { user=Model.UserName, title = Model.Title }, new { @class="actionlink" }) %> + <%= Html.ActionLink("Supprimer","Remove", new { user=Model.UserName, title = Model.Title }, new { @class="actionlink" } ) %> + <% } %> +
    +
    + +
    +
    + <% BBCodeHelper.Init(); %> +<%= BBCodeHelper.Parser.ToHtml(Model.Content) %> +
    + <% + string username = ""; + if (Membership.GetUser()!=null) + username = Membership.GetUser().UserName; %> + +<% foreach (var c in (Comment[])ViewData["Comments"]) { %> + +
    <%=c.From%> +<%= BBCodeHelper.Parser.ToHtml(c.CommentText) %> + <% if ( username == Model.UserName || c.From == username ) { %> + <%= Html.ActionLink("Supprimer","RemoveComment", new { cmtid = c.Id } )%> + <% } %> +
    +<% } %> +
    + <% using (Html.BeginForm("Comment","Blogs")) { %> + <%=Html.Hidden("UserName")%> + <%=Html.Hidden("Title")%> + <%=Html.TextArea("CommentText","")%> + <%=Html.Hidden("PostId",Model.Id)%> + + <% } %> +
    +
    +
    diff --git a/web/Views/Blogs/UserPosts.aspx b/web/Views/Blogs/UserPosts.aspx new file mode 100644 index 00000000..30809c65 --- /dev/null +++ b/web/Views/Blogs/UserPosts.aspx @@ -0,0 +1,42 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> +<%@ Register Assembly="Yavsc.WebControls" TagPrefix="yavsc" Namespace="Yavsc.WebControls" %> +<%=Html.Encode(ViewData["BlogTitle"])%> + +

    "> + " alt=""/> + <%=ViewData["BlogTitle"]%>

    +
    <%= Html.Encode(ViewData["Message"])%>
    +
    + + +<% + foreach (BlogEntry e in this.Model) { %> +
    style="background-color:#022;" <% } %>> + +

    <%= Html.ActionLink(e.Title,"UserPost", new { user=e.UserName, title = e.Title }) %>

    +
    (<%= e.Posted.ToString("yyyy/MM/dd") %> + - <%= e.Modified.ToString("yyyy/MM/dd") %> <%= e.Visible? "":", Invisible!" %>) +
    +<% if (Membership.GetUser()!=null) + if (Membership.GetUser().UserName==e.UserName) + { %> + <%= Html.ActionLink("Editer","Edit", new { user = e.UserName, title = e.Title }, new { @class="actionlink" }) %> + <%= Html.ActionLink("Supprimer","Remove", new { user = e.UserName, title = e.Title }, new { @class="actionlink" } ) %> + <% } %> +
    +<% } %> + +
    + <% + rp1.ResultCount = (int) ViewData["RecordCount"]; + rp1.CurrentPage = (int) ViewData["PageIndex"]; + user.Value = (string) ViewData["BlogUser"]; + +%> + + + +
    + + +
    \ No newline at end of file diff --git a/web/Views/FileSystem/Create.aspx b/web/Views/FileSystem/Create.aspx new file mode 100644 index 00000000..c994d646 --- /dev/null +++ b/web/Views/FileSystem/Create.aspx @@ -0,0 +1,20 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + +<% using(Html.BeginForm("Create", "FileSystem", FormMethod.Post, new { enctype = "multipart/form-data" })) { %> +
    + + + <%= Html.ValidationMessage("AFile") %> + +
    + + + +
    + + +
    + <% } %> +
    diff --git a/web/Views/FileSystem/Delete.aspx b/web/Views/FileSystem/Delete.aspx new file mode 100644 index 00000000..e6c14b90 --- /dev/null +++ b/web/Views/FileSystem/Delete.aspx @@ -0,0 +1,7 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + diff --git a/web/Views/FileSystem/Details.aspx b/web/Views/FileSystem/Details.aspx new file mode 100644 index 00000000..79bec8b3 --- /dev/null +++ b/web/Views/FileSystem/Details.aspx @@ -0,0 +1,15 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + +<%= Model.Name %>
    +Création : +<%= Model.CreationTime %>
    +Dérnière modification : +<%= Model.LastWriteTime %>
    +Dernier accès : +<%= Model.LastAccessTime %>
    +Lien permanent : ">/<%= ViewData["Content"] %> +
    diff --git a/web/Views/FileSystem/Edit.aspx b/web/Views/FileSystem/Edit.aspx new file mode 100644 index 00000000..4e92b60b --- /dev/null +++ b/web/Views/FileSystem/Edit.aspx @@ -0,0 +1,9 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + +<%= Html.ActionLink("Delete","FileSystem") %> +<%= Html.ActionLink("Rename","FileSystem") %> + diff --git a/web/Views/FileSystem/Index.aspx b/web/Views/FileSystem/Index.aspx new file mode 100644 index 00000000..345305d4 --- /dev/null +++ b/web/Views/FileSystem/Index.aspx @@ -0,0 +1,16 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + +

    Index of <%=ViewData["UserName"] %>'s files (<%= Html.Encode(Model.Count) %>)

    +
      +<% foreach (System.IO.FileInfo fi in Model) { %> +
    • <%= Html.ActionLink(fi.Name,"Details",new {id = fi.Name}) %>
    • +<% } %> +
    + +<%= Html.ActionLink("Ajouter des fichiers","Create") %> +
    diff --git a/web/Views/FrontOffice/Brand.aspx b/web/Views/FrontOffice/Brand.aspx new file mode 100644 index 00000000..a1177ab8 --- /dev/null +++ b/web/Views/FrontOffice/Brand.aspx @@ -0,0 +1,32 @@ +<%@ Page Title="Catalog" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +

    <% if (Model.Logo!=null) { %> + <%=Model.Logo.Alt%> + <% } %> + <%=Html.Encode(Model.Name)%>

    +

    <%=Html.Encode(Model.Slogan)%>

    +
    + +<% foreach (ProductCategory pc in Model.Categories ) { %> +
    +

    <%= Html.ActionLink( pc.Name, "ProductCategory", new { id = Model.Name, pc = pc.Reference }, new { @class="actionlink" } ) %>

    +
    + + <% foreach (Product p in pc.Products ) { %> +
    +

    <%= Html.ActionLink( p.Name, "Product", new { id = Model.Name, pc = pc.Reference , pref = p.Reference }, new { @class="actionlink" } ) %>

    +

    + <%= p.Description %> + <% if (p.Images !=null) + foreach (ProductImage i in p.Images ) { %> + <%=i.Alt%> + <% } %> +

    +
    +<% } %> +<% } %> + + +
    diff --git a/web/Views/FrontOffice/Catalog.aspx b/web/Views/FrontOffice/Catalog.aspx new file mode 100644 index 00000000..fdc51f15 --- /dev/null +++ b/web/Views/FrontOffice/Catalog.aspx @@ -0,0 +1,32 @@ +<%@ Page Title="Catalog" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + + + + +<% foreach (Brand b in Model.Brands ) { %>
    +

    <%= Html.ActionLink( b.Name, "Brand", new { id = b.Name }, new { @class="actionlink" } ) %>

    +

    <%= Html.Encode( b.Slogan ) %>

    + <% foreach (ProductCategory pc in b.Categories ) { %> +
    +

    <%= Html.ActionLink( pc.Name, "ProductCategory", new { id = b.Name, pc = pc.Reference }, new { @class="actionlink" } ) %>

    +
    + + <% foreach (Product p in pc.Products ) { %> +
    +

    <%= Html.ActionLink( p.Name, "Product", new { id = b.Name, pc = pc.Reference , pref = p.Reference }, new { @class="actionlink" } ) %>

    +

    + <%= p.Description %> + <% if (p.Images !=null) + foreach (ProductImage i in p.Images ) { %> + <%=i.Alt%> + <% } %> +

    +
    +<% } %> +<% } %> +
    <% } %> +
    + + diff --git a/web/Views/FrontOffice/Command.aspx b/web/Views/FrontOffice/Command.aspx new file mode 100644 index 00000000..65933f74 --- /dev/null +++ b/web/Views/FrontOffice/Command.aspx @@ -0,0 +1,7 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + diff --git a/web/Views/FrontOffice/Product.aspx b/web/Views/FrontOffice/Product.aspx new file mode 100644 index 00000000..0aeb5a48 --- /dev/null +++ b/web/Views/FrontOffice/Product.aspx @@ -0,0 +1,30 @@ +<%@ Page Title="Catalog" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + +<%= Html.Encode(Model.Name) %> + + +

    <%= Html.Encode(Model.Name) %>

    +<%= Html.Encode(Model.Reference) %>
    + +
    +

    <%= Html.Encode(Model.Description) %>

    +<% if (Model.Images!=null) foreach (ProductImage i in Model.Images) { %> +<%=i.Alt%> +<% } %> +<% if (Model.UnitaryPrice !=null) { %> +Prix unitaire : <%= Html.Encode(Model.UnitaryPrice.Quantity.ToString())%> +<%= Html.Encode(Model.UnitaryPrice.Unit.Name)%> +<% } else { %> Gratuit! <% } %> +
    +
    +<% if (Model.CommandForm!=null) { %> +Défaut de formulaire de commande!!! +<% } else { Response.Write( Html.CommandForm(Model,"Ajouter au panier")); } %> + +<% if (Model.CommandValidityDates!=null) { %> +Offre valable du <%= Model.CommandValidityDates.StartDate.ToString("dd/MM/yyyy") %> au +<%= Model.CommandValidityDates.EndDate.ToString("dd/MM/yyyy") %>. +<% } %> + +
    +
    diff --git a/web/Views/FrontOffice/ProductCategory.aspx b/web/Views/FrontOffice/ProductCategory.aspx new file mode 100644 index 00000000..063a6365 --- /dev/null +++ b/web/Views/FrontOffice/ProductCategory.aspx @@ -0,0 +1,23 @@ +<%@ Page Title="Catalog" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + + + +<% foreach (Product p in Model.Products ) { %> + +

    <%= Html.ActionLink( p.Name, "Product", new { id = ViewData["BrandName"], pc = Model.Reference , pref = p.Reference }, new { @class="actionlink" } ) %>

    + +

    + <%= p.Description %> + <% if (p.Images !=null) + foreach (ProductImage i in p.Images ) { %> + <%=i.Alt%> + <% } %> +

    + + + <% } %> + + +
    diff --git a/web/Views/FrontOffice/ReferenceNotFound.aspx b/web/Views/FrontOffice/ReferenceNotFound.aspx new file mode 100644 index 00000000..e6c14b90 --- /dev/null +++ b/web/Views/FrontOffice/ReferenceNotFound.aspx @@ -0,0 +1,7 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + diff --git a/web/Views/FrontOffice/Service.aspx b/web/Views/FrontOffice/Service.aspx new file mode 100644 index 00000000..d61c5e19 --- /dev/null +++ b/web/Views/FrontOffice/Service.aspx @@ -0,0 +1,31 @@ +<%@ Page Title="Catalog" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + +<%= Html.Encode(Model.Name) %> + + +

    <%=ViewData ["BrandName"]%> - <%=ViewData ["ProdCatName"]%> - <%= Html.ActionLink( Model.Name, "Product", new { id = ViewData ["BrandName"], pc = ViewData ["ProdCatRef"] , pref = Model.Reference } ) %>

    + +
    + +
    +

    <%= Html.Encode(Model.Description) %>

    +<% if (Model.Images!=null) foreach (ProductImage i in Model.Images) { %> +<%=i.Alt%> +<% } %> +<% if (Model.HourPrice !=null) { %> +Prix horaire de la prestation : +<%= Html.Encode(Model.HourPrice.Quantity.ToString())%> +<%= Html.Encode(Model.HourPrice.Unit.Name)%> +<% } %> +
    + +
    +<%= Html.CommandForm(Model,"Ajouter au panier") %> + +<% if (Model.CommandValidityDates!=null) { %> +Offre valable du <%= Model.CommandValidityDates.StartDate.ToString("dd/MM/yyyy") %> au +<%= Model.CommandValidityDates.EndDate.ToString("dd/MM/yyyy") %>. +<% } %> + +
    +
    diff --git a/web/Views/Home/AOEMail.aspx b/web/Views/Home/AOEMail.aspx new file mode 100644 index 00000000..e6c14b90 --- /dev/null +++ b/web/Views/Home/AOEMail.aspx @@ -0,0 +1,7 @@ +<%@ Page Language="C#" MasterPageFile="~/Models/App.master" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + diff --git a/web/Views/Home/Index.aspx b/web/Views/Home/Index.aspx new file mode 100644 index 00000000..c25d9f59 --- /dev/null +++ b/web/Views/Home/Index.aspx @@ -0,0 +1,8 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> +Indexe + +
    +<%= Html.ActionLink("blogs","Index","Blogs") %> +
    +
    + diff --git a/web/Views/Home/NCView.aspx b/web/Views/Home/NCView.aspx new file mode 100644 index 00000000..7f7a81d1 --- /dev/null +++ b/web/Views/Home/NCView.aspx @@ -0,0 +1,3 @@ +<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="" %> + + diff --git a/web/Views/Home/NView.aspx b/web/Views/Home/NView.aspx new file mode 100644 index 00000000..37fe01d5 --- /dev/null +++ b/web/Views/Home/NView.aspx @@ -0,0 +1,12 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> + + + + + + +
    + +
    + + diff --git a/web/Views/Home/Thanks.ascx b/web/Views/Home/Thanks.ascx new file mode 100644 index 00000000..11b0f5d6 --- /dev/null +++ b/web/Views/Home/Thanks.ascx @@ -0,0 +1,17 @@ +<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> +

    + <% var ts = ((string[,])ViewData["Thanks"]); + if (ts != null) { %> +


    Powered by
    + <% for (int i = 0; i <= ts.GetUpperBound(0); i++) + { + + %> + <%= "" + + ts[i,0]+"" + %> + <% + }} + %> +

    + diff --git a/web/Views/RegisterPage.cs b/web/Views/RegisterPage.cs new file mode 100644 index 00000000..7215e9f5 --- /dev/null +++ b/web/Views/RegisterPage.cs @@ -0,0 +1,28 @@ +using System; +using System.Web.UI.WebControls; +using yavscModel.RolesAndMembers; + + +namespace Yavsc +{ + public class RegisterPage : System.Web.Mvc.ViewPage + { + public RegisterPage () + { + } + + public CreateUserWizard Createuserwizard1; + + public void OnRegisterSendMail(object sender, MailMessageEventArgs e) + { + // Set MailMessage fields. + e.Message.IsBodyHtml = false; + e.Message.Subject = "New user on Web site."; + // Replace placeholder text in message body with information + // provided by the user. + e.Message.Body = e.Message.Body.Replace("<%PasswordQuestion%>", Createuserwizard1.Question); + e.Message.Body = e.Message.Body.Replace("<%PasswordAnswer%>", Createuserwizard1.Answer); +} + } +} + diff --git a/web/Views/Web.config b/web/Views/Web.config new file mode 100644 index 00000000..065b867b --- /dev/null +++ b/web/Views/Web.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/Views/WorkFlow/Index.aspx b/web/Views/WorkFlow/Index.aspx new file mode 100644 index 00000000..dd7860b9 --- /dev/null +++ b/web/Views/WorkFlow/Index.aspx @@ -0,0 +1,11 @@ +<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master"%> + + <%= "Index - " + Html.Encode(YavscHelpers.SiteName) + "" %> + + +
    +<%= Html.ActionLink("blogs","Index","WorkFlow") %> +
    + +
    + diff --git a/web/Views/WorkFlow/NewProject.aspx b/web/Views/WorkFlow/NewProject.aspx new file mode 100644 index 00000000..7ae525e7 --- /dev/null +++ b/web/Views/WorkFlow/NewProject.aspx @@ -0,0 +1,22 @@ +<%@ Page Title="Nouveau projet" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Models/App.master" %> + + + +
    +<%= Html.ValidationSummary("Nouveau projet") %> +<% using ( Html.BeginForm("NewProject", "WorkFlow") ) { %> +<%= Html.LabelFor(model => model.Name) %> : +<%= Html.TextBox( "Name" ) %> +<%= Html.ValidationMessage("Name", "*") %>
    +<%= Html.LabelFor(model => model.Manager) %> : +<%= Html.TextBox( "Manager" ) %> +<%= Html.ValidationMessage("Manager", "*") %>
    +<%= Html.LabelFor(model => model.Description) %> : +<%= Html.TextBox( "Description" ) %> +<%= Html.ValidationMessage("Description", "*") %>
    + +<% } %> +
    +
    + + diff --git a/web/Web.config b/web/Web.config new file mode 100644 index 00000000..b5fe46e4 --- /dev/null +++ b/web/Web.config @@ -0,0 +1,215 @@ + + + + + + +
    + +
    +
    +
    +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/Web.csproj b/web/Web.csproj new file mode 100644 index 00000000..25f1c718 --- /dev/null +++ b/web/Web.csproj @@ -0,0 +1,260 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {77044C92-D2F1-45BD-80DD-AA25B311B027} + {349C5851-65DF-11DA-9384-00065B846F21};{603C0E0B-DB56-11DC-BE95-000D561079B0};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Yavsc + v4.5 + + + true + full + false + bin + DEBUG;TEST + prompt + 4 + false + + + + Yavsc + true + + + none + true + bin + prompt + 4 + false + Yavsc + true + + + false + bin + DEBUG,TEST,WEBAPI + 4 + maeweb + true + + + + + + + + + + + + + + + + + + + + + False + + + lib\CodeKicker.BBCode.dll + + + False + + + False + + + + + + + + False + monodevelop + + + ..\..\..\..\..\usr\lib\mono\4.5\System.Web.Http.WebHost.dll + False + + + + + False + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + Global.asax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {BBA7175D-7F92-4278-96FC-84C495A2B5A6} + NpgsqlMRPProviders + + + {C6E9E91B-97D3-48D9-8AA7-05356929E162} + NpgsqlBlogProvider + + + {90BF2234-7252-4CD5-B2A4-17501B19279B} + SalesCatalog + + + {821FF72D-9F4B-4A2C-B95C-7B965291F119} + WorkFlowProvider + + + {68F5B80A-616E-4C3C-91A0-828AA40000BD} + yavscModel + + + {59E1DF7B-FFA0-4DEB-B5F3-76EBD98D5356} + WebControls + + + diff --git a/web/WebDeploy.targets b/web/WebDeploy.targets new file mode 100644 index 00000000..43660ada --- /dev/null +++ b/web/WebDeploy.targets @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrorPages.sln b/web/errors/CustomErrorPages/CustomErrorPages.sln new file mode 100644 index 00000000..b4fe3c23 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrorPages.sln @@ -0,0 +1,9 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + EndGlobalSection +EndGlobal diff --git a/web/errors/CustomErrorPages/CustomErrorPages.userprefs b/web/errors/CustomErrorPages/CustomErrorPages.userprefs new file mode 100644 index 00000000..aa4d9b8b --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrorPages.userprefs @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/web/errors/CustomErrorPages/CustomErrors1/AssemblyInfo.cs b/web/errors/CustomErrorPages/CustomErrors1/AssemblyInfo.cs new file mode 100644 index 00000000..cced87bf --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/AssemblyInfo.cs @@ -0,0 +1,62 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the "project output directory". The location of the project output +// directory is dependent on whether you are working with a local or web project. +// For local projects, the project output directory is defined as +// \obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// For web projects, the project output directory is defined as +// %HOMEPATH%\VSWebCache\\\obj\. +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/web/errors/CustomErrorPages/CustomErrors1/CustomErrors1.csproj b/web/errors/CustomErrorPages/CustomErrors1/CustomErrors1.csproj new file mode 100644 index 00000000..64572a63 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/CustomErrors1.csproj @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors1/Default.aspx b/web/errors/CustomErrorPages/CustomErrors1/Default.aspx new file mode 100644 index 00000000..777ee40d --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Default.aspx @@ -0,0 +1,11 @@ +<%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors1._Default" %> + + + + Default page + + +
    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors1/Default.aspx.cs b/web/errors/CustomErrorPages/CustomErrors1/Default.aspx.cs new file mode 100644 index 00000000..d0775ca6 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Default.aspx.cs @@ -0,0 +1,41 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors1 +{ + /// + /// Summary description for _Default. + /// + public class _Default : PageBase + { + private void Page_Load (object sender, System.EventArgs e) + { + // ------------------------------------------------------ + // No one is sane mind would throw an exception just for + // the heck of it, but for demonstration purposes this + // should work. + // ------------------------------------------------------ + throw new Exception ("Silly exception"); + } + + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors1/Default.aspx.resx b/web/errors/CustomErrorPages/CustomErrors1/Default.aspx.resx new file mode 100644 index 00000000..7f99b555 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Default.aspx.resx @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + Private + + + False + + \ No newline at end of file diff --git a/web/errors/CustomErrorPages/CustomErrors1/Global.asax b/web/errors/CustomErrorPages/CustomErrors1/Global.asax new file mode 100644 index 00000000..2fc937da --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CustomErrors1.Global" %> diff --git a/web/errors/CustomErrorPages/CustomErrors1/Global.asax.cs b/web/errors/CustomErrorPages/CustomErrors1/Global.asax.cs new file mode 100644 index 00000000..d5da8f54 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Global.asax.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Web; +using System.Web.SessionState; + +namespace CustomErrors1 +{ + /// + /// Summary description for Global. + /// + public class Global : System.Web.HttpApplication + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + public Global() + { + InitializeComponent(); + } + + protected void Application_Start(Object sender, EventArgs e) + { + + } + + protected void Session_Start(Object sender, EventArgs e) + { + + } + + protected void Application_BeginRequest(Object sender, EventArgs e) + { + + } + + protected void Application_EndRequest(Object sender, EventArgs e) + { + + } + + protected void Application_AuthenticateRequest(Object sender, EventArgs e) + { + + } + + protected void Application_Error(Object sender, EventArgs e) + { + + } + + protected void Session_End(Object sender, EventArgs e) + { + + } + + protected void Application_End(Object sender, EventArgs e) + { + + } + + #region Web Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + } + #endregion + } +} + diff --git a/web/errors/CustomErrorPages/CustomErrors1/Global.asax.resx b/web/errors/CustomErrorPages/CustomErrors1/Global.asax.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Global.asax.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors1/PageBase.cs b/web/errors/CustomErrorPages/CustomErrors1/PageBase.cs new file mode 100644 index 00000000..1102ad8b --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/PageBase.cs @@ -0,0 +1,32 @@ +using System; +using System.Web; +using System.Web.UI; + +namespace AspNetResources.CustomErrors1 +{ + public class PageBase : System.Web.UI.Page + { + protected override void OnError(EventArgs e) + { + // At this point we have information about the error + HttpContext ctx = HttpContext.Current; + + Exception exception = ctx.Server.GetLastError (); + + string errorInfo = "
    Offending URL: " + ctx.Request.Url.ToString () + + "
    Source: " + exception.Source + + "
    Message: " + exception.Message + + "
    Stack trace: " + exception.StackTrace; + + ctx.Response.Write (errorInfo); + + // -------------------------------------------------- + // To let the page finish running we clear the error + // -------------------------------------------------- + ctx.Server.ClearError (); + + base.OnError (e); + } + + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors1/Web.config b/web/errors/CustomErrorPages/CustomErrors1/Web.config new file mode 100644 index 00000000..43f74faf --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors1/Web.config @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors2/AssemblyInfo.cs b/web/errors/CustomErrorPages/CustomErrors2/AssemblyInfo.cs new file mode 100644 index 00000000..cced87bf --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/AssemblyInfo.cs @@ -0,0 +1,62 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the "project output directory". The location of the project output +// directory is dependent on whether you are working with a local or web project. +// For local projects, the project output directory is defined as +// \obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// For web projects, the project output directory is defined as +// %HOMEPATH%\VSWebCache\\\obj\. +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/web/errors/CustomErrorPages/CustomErrors2/CustomErrors2.csproj b/web/errors/CustomErrorPages/CustomErrors2/CustomErrors2.csproj new file mode 100644 index 00000000..295fbe9c --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/CustomErrors2.csproj @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors2/Default.aspx b/web/errors/CustomErrorPages/CustomErrors2/Default.aspx new file mode 100644 index 00000000..3e402345 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Default.aspx @@ -0,0 +1,12 @@ +<%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors2._Default" %> + + + + Default + + +
    + +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors2/Default.aspx.cs b/web/errors/CustomErrorPages/CustomErrors2/Default.aspx.cs new file mode 100644 index 00000000..f1233611 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Default.aspx.cs @@ -0,0 +1,39 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors2 +{ + /// + /// Summary description for _Default. + /// + public class _Default : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + // ------------------------------------------------------ + // No one is sane mind would throw an exception just for + // the heck of it, but for demonstration purposes this + // should work. Your event handler in Global.asax will + // catch the exception. + // ------------------------------------------------------ + throw new Exception ("Silly exception"); + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors2/Default.aspx.resx b/web/errors/CustomErrorPages/CustomErrors2/Default.aspx.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Default.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors2/Global.asax b/web/errors/CustomErrorPages/CustomErrors2/Global.asax new file mode 100644 index 00000000..50b4978e --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CustomErrors2.Global" %> diff --git a/web/errors/CustomErrorPages/CustomErrors2/Global.asax.cs b/web/errors/CustomErrorPages/CustomErrors2/Global.asax.cs new file mode 100644 index 00000000..36f66bed --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Global.asax.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Web; +using System.Web.SessionState; + +namespace CustomErrors2 +{ + /// + /// Summary description for Global. + /// + public class Global : System.Web.HttpApplication + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + public Global() + { + InitializeComponent(); + } + + protected void Application_Start(Object sender, EventArgs e) + { + + } + + protected void Session_Start(Object sender, EventArgs e) + { + + } + + protected void Application_BeginRequest(Object sender, EventArgs e) + { + + } + + protected void Application_EndRequest(Object sender, EventArgs e) + { + + } + + protected void Application_AuthenticateRequest(Object sender, EventArgs e) + { + + } + + protected void Application_Error(Object sender, EventArgs e) + { + // At this point we have information about the error + HttpContext ctx = HttpContext.Current; + + Exception exception = ctx.Server.GetLastError (); + + string errorInfo = "
    Offending URL: " + ctx.Request.Url.ToString () + + "
    Source: " + exception.Source + + "
    Message: " + exception.Message + + "
    Stack trace: " + exception.StackTrace; + + ctx.Response.Write (errorInfo); + + // -------------------------------------------------- + // To let the page finish running we clear the error + // -------------------------------------------------- + ctx.Server.ClearError (); + } + + protected void Session_End(Object sender, EventArgs e) + { + + } + + protected void Application_End(Object sender, EventArgs e) + { + + } + + #region Web Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + } + #endregion + } +} + diff --git a/web/errors/CustomErrorPages/CustomErrors2/Global.asax.resx b/web/errors/CustomErrorPages/CustomErrors2/Global.asax.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Global.asax.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors2/Web.config b/web/errors/CustomErrorPages/CustomErrors2/Web.config new file mode 100644 index 00000000..43f74faf --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors2/Web.config @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/AssemblyInfo.cs b/web/errors/CustomErrorPages/CustomErrors3/AssemblyInfo.cs new file mode 100644 index 00000000..cced87bf --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/AssemblyInfo.cs @@ -0,0 +1,62 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the "project output directory". The location of the project output +// directory is dependent on whether you are working with a local or web project. +// For local projects, the project output directory is defined as +// \obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// For web projects, the project output directory is defined as +// %HOMEPATH%\VSWebCache\\\obj\. +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/web/errors/CustomErrorPages/CustomErrors3/CustomErrors3.csproj b/web/errors/CustomErrorPages/CustomErrors3/CustomErrors3.csproj new file mode 100644 index 00000000..22676070 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/CustomErrors3.csproj @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/Default.aspx b/web/errors/CustomErrorPages/CustomErrors3/Default.aspx new file mode 100644 index 00000000..974aba6f --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Default.aspx @@ -0,0 +1,17 @@ +<%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors3._Default" %> + + + + Default + + +
    +

    To see custom error pages +

      +
    1. request a page that doesn't exist, eg: test.aspx, or
    2. +
    3. uncomment the code in Page_OnLoad and let it throw an exception
    4. +
    +

    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/Default.aspx.cs b/web/errors/CustomErrorPages/CustomErrors3/Default.aspx.cs new file mode 100644 index 00000000..7d71806e --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Default.aspx.cs @@ -0,0 +1,39 @@ +using System; +using System.Web; +using System.Web.UI; + +namespace AspNetResources.CustomErrors3 +{ + /// + /// Summary description for _Default. + /// + public class _Default : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + // ------------------------------------------------------ + // No one is sane mind would throw an exception just for + // the heck of it, but for demonstration purposes this + // should work. + // ------------------------------------------------------ + // throw new Exception ("Silly exception"); + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors3/Default.aspx.resx b/web/errors/CustomErrorPages/CustomErrors3/Default.aspx.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Default.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/Global.asax b/web/errors/CustomErrorPages/CustomErrors3/Global.asax new file mode 100644 index 00000000..611e4d65 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CustomErrors3.Global" %> diff --git a/web/errors/CustomErrorPages/CustomErrors3/Global.asax.cs b/web/errors/CustomErrorPages/CustomErrors3/Global.asax.cs new file mode 100644 index 00000000..39f4149f --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Global.asax.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Web; +using System.Web.SessionState; + +namespace CustomErrors3 +{ + /// + /// Summary description for Global. + /// + public class Global : System.Web.HttpApplication + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + public Global() + { + InitializeComponent(); + } + + protected void Application_Start(Object sender, EventArgs e) + { + + } + + protected void Session_Start(Object sender, EventArgs e) + { + + } + + protected void Application_BeginRequest(Object sender, EventArgs e) + { + + } + + protected void Application_EndRequest(Object sender, EventArgs e) + { + + } + + protected void Application_AuthenticateRequest(Object sender, EventArgs e) + { + + } + + protected void Application_Error(Object sender, EventArgs e) + { + + } + + protected void Session_End(Object sender, EventArgs e) + { + + } + + protected void Application_End(Object sender, EventArgs e) + { + + } + + #region Web Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + } + #endregion + } +} + diff --git a/web/errors/CustomErrorPages/CustomErrors3/Global.asax.resx b/web/errors/CustomErrorPages/CustomErrors3/Global.asax.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Global.asax.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/Web.config b/web/errors/CustomErrorPages/CustomErrors3/Web.config new file mode 100644 index 00000000..765207b5 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/Web.config @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx b/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx new file mode 100644 index 00000000..8e6f7b25 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" Codebehind="GeneralError.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors3.GeneralError" %> + + + + Server error + + +
    +

    Sorry

    +

    The server is experiencing a problem with the page you requested. We apologize for + the inconvenience. We will resolve this issue shortly.

    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.cs b/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.cs new file mode 100644 index 00000000..247d0184 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.cs @@ -0,0 +1,32 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors3 +{ + /// + /// Summary description for GeneralError. + /// + public class GeneralError : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.resx b/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.resx new file mode 100644 index 00000000..97063148 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/errors/GeneralError.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms9 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Culture=neutral + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx b/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx new file mode 100644 index 00000000..51c96687 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" Codebehind="PageNotFound.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors3.PageNotFound" %> + + + + PageNotFound + + +
    +

    Sorry

    +

    We cannot find the page you are looking for. We apologize for + the inconvenience. We will resolve this issue shortly.

    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.cs b/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.cs new file mode 100644 index 00000000..0a2abb1f --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.cs @@ -0,0 +1,32 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors3 +{ + /// + /// Summary description for PageNotFound. + /// + public class PageNotFound : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.resx b/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.resx new file mode 100644 index 00000000..3f337e08 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors3/errors/PageNotFound.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/AssemblyInfo.cs b/web/errors/CustomErrorPages/CustomErrors4/AssemblyInfo.cs new file mode 100644 index 00000000..cced87bf --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/AssemblyInfo.cs @@ -0,0 +1,62 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the "project output directory". The location of the project output +// directory is dependent on whether you are working with a local or web project. +// For local projects, the project output directory is defined as +// \obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// For web projects, the project output directory is defined as +// %HOMEPATH%\VSWebCache\\\obj\. +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/web/errors/CustomErrorPages/CustomErrors4/CustomErrors4.csproj b/web/errors/CustomErrorPages/CustomErrors4/CustomErrors4.csproj new file mode 100644 index 00000000..3ef63f47 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/CustomErrors4.csproj @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/Default.aspx b/web/errors/CustomErrorPages/CustomErrors4/Default.aspx new file mode 100644 index 00000000..839f3fac --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Default.aspx @@ -0,0 +1,11 @@ +<%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors4._Default" %> + + + + WebForm1 + + +
    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/Default.aspx.cs b/web/errors/CustomErrorPages/CustomErrors4/Default.aspx.cs new file mode 100644 index 00000000..8ed47d66 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Default.aspx.cs @@ -0,0 +1,40 @@ +using System; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace AspNetResources.CustomErrors4 +{ + /// + /// Summary description for _Default. + /// + public class _Default : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + // ------------------------------------------------------ + // No one is sane mind would throw an exception just for + // the heck of it, but for demonstration purposes this + // should work. + // ------------------------------------------------------ + //throw new Exception ("Silly exception"); + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors4/Default.aspx.resx b/web/errors/CustomErrorPages/CustomErrors4/Default.aspx.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Default.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/ErrorModule.cs b/web/errors/CustomErrorPages/CustomErrors4/ErrorModule.cs new file mode 100644 index 00000000..6496d03d --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/ErrorModule.cs @@ -0,0 +1,35 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors4 +{ + public class MyErrorModule : IHttpModule + { + public void Init (HttpApplication app) + { + app.Error += new System.EventHandler (OnError); + } + + public void OnError (object obj, EventArgs args) + { + // At this point we have information about the error + HttpContext ctx = HttpContext.Current; + + Exception exception = ctx.Server.GetLastError (); + + string errorInfo = "
    Offending URL: " + ctx.Request.Url.ToString () + + "
    Source: " + exception.Source + + "
    Message: " + exception.Message + + "
    Stack trace: " + exception.StackTrace; + + ctx.Response.Write (errorInfo); + + // -------------------------------------------------- + // To let the page finish running we clear the error + // -------------------------------------------------- + //ctx.Server.ClearError (); + } + + public void Dispose () {} + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors4/Global.asax b/web/errors/CustomErrorPages/CustomErrors4/Global.asax new file mode 100644 index 00000000..14794241 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CustomErrors4.Global" %> diff --git a/web/errors/CustomErrorPages/CustomErrors4/Global.asax.cs b/web/errors/CustomErrorPages/CustomErrors4/Global.asax.cs new file mode 100644 index 00000000..128864c7 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Global.asax.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Web; +using System.Web.SessionState; + +namespace CustomErrors4 +{ + /// + /// Summary description for Global. + /// + public class Global : System.Web.HttpApplication + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + public Global() + { + InitializeComponent(); + } + + protected void Application_Start(Object sender, EventArgs e) + { + + } + + protected void Session_Start(Object sender, EventArgs e) + { + + } + + protected void Application_BeginRequest(Object sender, EventArgs e) + { + + } + + protected void Application_EndRequest(Object sender, EventArgs e) + { + + } + + protected void Application_AuthenticateRequest(Object sender, EventArgs e) + { + + } + + protected void Application_Error(Object sender, EventArgs e) + { + + } + + protected void Session_End(Object sender, EventArgs e) + { + + } + + protected void Application_End(Object sender, EventArgs e) + { + + } + + #region Web Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + } + #endregion + } +} + diff --git a/web/errors/CustomErrorPages/CustomErrors4/Global.asax.resx b/web/errors/CustomErrorPages/CustomErrors4/Global.asax.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Global.asax.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/Web.config b/web/errors/CustomErrorPages/CustomErrors4/Web.config new file mode 100644 index 00000000..e2ed8087 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/Web.config @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx b/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx new file mode 100644 index 00000000..8e6f7b25 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" Codebehind="GeneralError.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors3.GeneralError" %> + + + + Server error + + +
    +

    Sorry

    +

    The server is experiencing a problem with the page you requested. We apologize for + the inconvenience. We will resolve this issue shortly.

    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.cs b/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.cs new file mode 100644 index 00000000..247d0184 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.cs @@ -0,0 +1,32 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors3 +{ + /// + /// Summary description for GeneralError. + /// + public class GeneralError : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.resx b/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/errors/GeneralError.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx b/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx new file mode 100644 index 00000000..51c96687 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" Codebehind="PageNotFound.aspx.cs" AutoEventWireup="false" Inherits="AspNetResources.CustomErrors3.PageNotFound" %> + + + + PageNotFound + + +
    +

    Sorry

    +

    We cannot find the page you are looking for. We apologize for + the inconvenience. We will resolve this issue shortly.

    +
    + + diff --git a/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.cs b/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.cs new file mode 100644 index 00000000..0a2abb1f --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.cs @@ -0,0 +1,32 @@ +using System; +using System.Web; + +namespace AspNetResources.CustomErrors3 +{ + /// + /// Summary description for PageNotFound. + /// + public class PageNotFound : System.Web.UI.Page + { + private void Page_Load(object sender, System.EventArgs e) + { + } + + #region Web Form Designer generated code + override protected void OnInit(EventArgs e) + { + InitializeComponent(); + base.OnInit(e); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.Load += new System.EventHandler(this.Page_Load); + } + #endregion + } +} diff --git a/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.resx b/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/web/errors/CustomErrorPages/CustomErrors4/errors/PageNotFound.aspx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/web/errors/GeneralError.aspx b/web/errors/GeneralError.aspx new file mode 100644 index 00000000..969463d1 --- /dev/null +++ b/web/errors/GeneralError.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" AutoEventWireup="false" %> + + + + Server error + + +
    +

    Sorry

    +

    The server is experiencing a problem with the page you requested. We apologize for + the inconvenience. We will resolve this issue shortly.

    +
    + + diff --git a/web/errors/PageNotFound.aspx b/web/errors/PageNotFound.aspx new file mode 100644 index 00000000..f17d94e1 --- /dev/null +++ b/web/errors/PageNotFound.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" AutoEventWireup="false" %> + + + + PageNotFound + + +
    +

    Sorry

    +

    We cannot find the page you are looking for. We apologize for + the inconvenience. We will resolve this issue shortly.

    +
    + + diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c73dc91a00c32284aa3b1c271b3cbc76665f5960 GIT binary patch literal 2238 zcmeHEZA_C_6n+?+g}JS(Oq^3b1VIMM7%)YY4?hO%gO5TfpKa;wTHu0_5kOLeBA^(z zQ2nuN{9%EFWyZH&)<_YC=sV z&Y3E4wpO4DXUtXjypAGau3o^1xdtOXYc%3C;ZzfG!l`B>PFkz+iK7Oy4ijcvgjN%# z+iLM~hZ$3yW=wY1Bb9fbTl zZfy4tVB0SP*g8Le++PnO=k6eK0)xoDH-xO<5Hjz3knzU|Hb0>Fa2V--4kLq*_SYe# zJ`xzgCc*}F6dTnMB&cIZBA!A#k$5ukRO0K@BZyZIlWvT3qgYSpB;qN=mu-0i|HlUS zvi-LW#MUv+mcGIe{T3rzS`b~p+MKqf1uJu0>2aAgVFly$i|;aQwoxLcSi7Oj#+Z4L zz>sVgrDv-&!L}`h);)^^FSW>HqBA_hYbA^7krr8qDs2d--w6@tO7Zd)Z)%O1;eKAb zQ3@D0i2BocS|O#aJk-~;K@!UfE;si|sL>KCbIS{o<&vk8ev?ZcBbwgU1S~&V5c^XG ztv^0Axpoa>rnOX{PQCP;ud!+?v+WdZZ#Yw*6OpZ#p4=*<)@c_B{$!F>M#nQEh)U$^ zje_pBW{AMC_f_)ZaWatGu5G4SB*@sy!s~>S{X9$l|7`0MGR2(<6nBZ~LYCG}I#wAY zkBsf0s6CnUYLQEBb=pmNt7W;UB3mbZS-wGL$i=OD@p(Be=TSPn94uTC(ICHnW*&3( zU)p=5iy#aO6xq~?LcKbkpi{4S{i@=9u%KKC&MQjrjz18*t0=zje1Xw9pMQMH7w}H` e6vY}0_`klV_=^_26OVpN(0Lvf>DAvos`@ubGmeD- literal 0 HcmV?d00001 diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1abcbea63ae3cd46cb20cb8ee8bc7b2b509c6de4 GIT binary patch literal 3295 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 literal 0 HcmV?d00001 diff --git a/web/genpot.sh b/web/genpot.sh new file mode 100644 index 00000000..f3b4d0d5 --- /dev/null +++ b/web/genpot.sh @@ -0,0 +1,9 @@ +Le script a débuté sur ven. 03 janv. 2014 00:34:11 CET +paul@pazms:~/workspace/mae/mae$ ../GettextNet/Bin/Release/GNU.Gettext.Xgettext.exe -D ./ --recursive -o ./po/Message s.pot +Template file '/home/paul/workspace/mae/mae/po/Messages.pot' generated +paul@pazms:~/workspace/mae/mae$ ../GettextNet/Bin/Release/GNU.Gettext.Msgfmt.exe -l fr-FR -d ../bin/Debug -r Examples .Hello.Messages -L ../../Bin/Debug fr.po +File fr.po not found +Error accepting options +paul@pazms:~/workspace/mae/mae$ exit + +Script terminé sur ven. 03 janv. 2014 00:35:36 CET diff --git a/web/images/Banner.png b/web/images/Banner.png new file mode 100644 index 0000000000000000000000000000000000000000..12dfaa2becf167b2bc94f7037823ce03ff1842d4 GIT binary patch literal 93007 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஫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 ULmX7)+&3;WWB3L9zi#*c50E%+A^-pY literal 0 HcmV?d00001 diff --git a/web/images/Mono-powered.png b/web/images/Mono-powered.png new file mode 100644 index 0000000000000000000000000000000000000000..3f69e4f5e9cec170e9af4d63669afe137b1b35a8 GIT binary patch literal 1676 zcmV;726Op|P)<# zGF4Yp;2aoQRa912T3cOOU0z{)R8n7IUSeT;Wo2k(W@Be#acpgBZESGqIX7@^dU0)q zbaixmeS3j@jDv-Ug@%OiT3VrhfRBxrj*yLyjiHZ_lkRYEq@k;(sHE|Yis_e^v$V6l zzP-oD$Hmje&(Y4-)Y$aO$@|*b>FVk8_44`q`2GLMh53JO$cX>%ZHZDD6+Aa`MNAY*c6 zVRU6=Aa!$TZf77zX>D*WAV+C!a3E=OAZBu9Wgv5JW^{L9a%CV2VRIm4WoBt^Wn>^? zc_4IXWgtd!Wn~~!Z)S9NVRB_4MsIa)WMOn^Z*CxAZe$>7b0A@MVQFk(Vr*p!W^ZyJ zWN&wFY;R#?AYpVMXmoUNIxjDGcXuvlX>D*WZ*pfwS{4fc00e|dL_t(|+O?K_W1=_^ z#_{Swve+iQ2;nG-Yengmy3hq0TLRzzTkYfp(O&QV+eZv>)E|$N%!qU2{4Nz|9pN~R zv-6n4ambAh<8jt`o*goygPJe}PL(zrcOf( z3?r;wU*ILb`p4SG9>y8|{UaY)I$_g>gP$r}lnMW9^C0PmC6&?+V zXTxyC5$x`(O0xW+S-7r*`q6Q)`tv%umgBUtF33lE4sz=PK+GqQhsf6DDPU1@89ywO+g=0%Wei`30Dt!TBYa zQtui}qeI(`Py^l?@XCOL3H&J)IikJ>t1!koOalwX4N#@DP$@fUz=_TA=-591_|xL$ znCa_XE*>Qo+)Ozz=+pCdefMA-qkhOq;Pu9F59?S@+pV|Y9+q$nyEvG@{gtHL-`y!N zSdMYkF{Z|V5Y|;m0AO~T}}5OZrYFPK+q&YrrH|6=s{t~2qlCB(2Blt ztd>s7(*y=__*`HcW~8{fVd{=KHnvc;%fP-MR6E{WfVEp7pYHGN;;H3xobO9#Y{d%9 zZ6Ags)KKdg*r^B!p`RS%Y&^S^V;g_0vd}x}y0@LeM$Wh(P zNr4{?IC9=Uo&fyz)`9Dts6`%Sji}Qm--%t`6m7GEXq~rB$_jX!jgBD|n%C6bNG@MA zn2~SZ?B>>hm170Yk8Lc9Rn-(#AqwcXSyAsqma20Mg92;E$JBsN>-DxgS@Qn=;o;HQ zW&iwqeSQD;&f`KNK;%D;TxAB6Vuu9>Fl^@p0dDvNYh3 zd~>% zTbb<;*j*ejyW{MRhQcRj$CYdkhvT!-%cRooWAw*z@pOA$Jhk0SahS>rMrx@3o&gM% z7x@2sU*Q{YfM&Drw~oGDv6V5FT@YBG({={Cl-g9-+n+Q|u5W%4UC_`g7@5t8sXQJ; z8g44@Ty|seG2JZ!4Nl<;ky&z6s)6xje`z?H87IVu(twOpHTYP|_k9cx|F_+0I==w2 Wv^r-KKSSRD0000!QK literal 0 HcmV?d00001 diff --git a/web/images/apache_pb.gif b/web/images/apache_pb.gif new file mode 100644 index 0000000000000000000000000000000000000000..f8cba34d603de6cc769241f35248cb32c779e425 GIT binary patch literal 2339 zcmeH`{Xf%*1HeC@J$V|&(B?*)Smxq2ImPm+kIDGw)4 zv3x~Dhr=`%;ZC!rxTcftOIvi&gQv=Nulp~)KivB-c)#AS*V~ujbY2^67dh5Zf4=~=%deV#r(vWB<8VNmzPDa`gB`oBE~Yrf*qu-ZjKU zGyjj5Z%*CRf#X&aQ3+s+0qiT8B1Pp6`fJH>Y&QQ;2O`HDPo1K&s$dhk)@&+O&{BD4C)bv1pxvPn*wcEev#CT1o%&x!o?D3;qZ@4{X{_CU+3-BYwS#w&u)JyF#JS zyHpQq`ZnBqYLBY3Ybf*m8x7~~-AL%a-o?J*57rV}u)W)*!a`qwSqID_P2!j!D7E*k zOw$khjvrF*oM0aDQ?BWYl>Zj)BOH$&5-3tUoqZH1dUS@%sO^cNFM>9j!sN$hwu2Qg zG?NVSzhKHD5i*O4sH3%8XadtaZzd}9=*YtL6IR`3R|*r0H=~0^79*@&yCYa*?mPoe z6Pl!j(-2M+Wi@!kbP)ibDB;&02LXiKGX~egg*bCE{_4e_zq1WFgEY|M49?#+! zf4*TOjMCL6^09G}Kitc(d_JTzz=oMgzjUoUDJh-K6jU`_Q(oyaJ#K!LFUksn!L8#Z zr_~n}qNZz6saQ7OIe{wSSz61u5Zy>3HNDv^1nrp-v(VBqaV)Mp0%kIASb^q{Zq*xO zO4@`bA>>#-de0~qQlh>T4&_)eTNy;k^y_{j5FXMg{3R^8wNuKn?}^FpAG$XX=#vny zYIx{_YNKwo%Ah;o@bWRcemY@?_f)0a5JyuAx~6_g!X+{ z@PoW5M2u``#$t~|29Yy%chiuKZR?7p_T2RrC=-#wGtpDE2{+$_H>(GqSY`E;3mtZg zc=pFdM$d!Y#UK7G;uV)5+%{gH@xa6-yQbmNqB0;BLUATU%Q5ARs~r=AAFbl zCP$fC2u0djsDKGq<4>i_cGUZy{<_WlI9n^uz&Jqn&4cQSOaOAOQamuI~FRvOM zUJPH&#^T1{E)^w)b}(qfa-BPU^Jj;wJ4v>~{5GkXCfNu#l8*!L$@%ZSdpAe?@{N+4 zoT5^Y+V{+|>LM-K(zuuVdZ*VW(n0ytZP;TQ=tK~mma3PawnZULE*Gq4)tMO<(nTbB zu_PzXn$(3d$Vui_%|@=fNCw|s?Z7u22z8oLx{Y|@)5~>^nvpNzp7%LC- z#~d+uDe*Kd#dlXfc^lFw_?Lqw}7!jw1RPe#aiSOuS#z#*?_kB zt#;@T_5EPh&`TPuXy!-UvD3f)K41)kEbnTi;`;~Bqt-f?rfwzd|Lv(XYrU&Zzm4Pj LHR~HV3^?#N_v!P+ literal 0 HcmV?d00001 diff --git a/web/images/apache_pbw.gif b/web/images/apache_pbw.gif new file mode 100644 index 0000000000000000000000000000000000000000..b0fe4008a52fbd23533c4ff673b7a945318fb363 GIT binary patch literal 1640 zcmV-u2ABCqNk%w1VFLjm0E7Sl0000X7#J}C|6>6EoB;p-02u!OWB&l0?*RY*F#uXx zTD?*b|3VmRYisXHjB|5y?^0vuO7Db(g#Uy9-h1BXgq)?NrSF_V)}_wgt%SY3#{bR$ z|IQfB&c^@${{R30A^s6Va%Ew3Wn>_CX>@2HM@dak03rDV0SW*g04x9i00094AOHXb z{@^E$WNDsgs;(^Sc_RGI^xNKeuJ3&B|GOHjH2VmT$fR;P1UjG4sB}7FTCdnFjmqtM zzd)^cOfG`Y==67HX}8O8n&vI1Gu8OKRFl&9gD(L9gM$ija0-Jpi2zr6kB~eT0emKH z4V4@g6PqbCf&dnb5*`{73KAL~q6(@C52XsNr4Oku4+<6==fpGe zgOmz+sAuMx!Gj+(1PCBuL<0%yJ{VA7;D7;b+Y%(0z(G}@LZCDNR3PXc09ob!>an9F z;pD(`!cMw_HF8|BLX3t15V^A;!k^8eF;vx{!GjM62pmB0z~V%08YggLFzK8$b^u`Q z3$=COJ9J&gfokJ!VM(l{7%d`Jk0(K&K;!B$1uD_H0RspONNRvU#RC|jhMd7uYdfAN z?RjV!%FRo7FA`lPTgY9bn~ksFM-nt4(zpPQ9(9B1sHTw2oPXo zbc_x0%=N$|WO652z2vu+A27{ZKr2_nrwu;<0-%>Ry;OD50|!VB(x!mH0(_KSw1kYV z7d}`eX>2WTnNV?nq=0u`P9Kei28k3rjLwfV>C>hurBq)BJaAC~2_XKMzyjS^&{1bd z%)x{%hvWxWeHcoii!2W`fD~S&^(UPI0w|yt0SN4+)BqD5m;eA7c{71*3_y5@7CZsd zM20*@;fEi(AhjZh{PpMG00Nx2+KL7=d0;lKZ8M{6I^Jjn1pye+rOApVthB8u0o_E!V1JsBHS51Jqbmv}znB{l^RSRH_Rm3gLgr6rl<0I3BkCU)2v z=wgD})Hnrc15j|oX_#iJsiqWQzybvkgc<=39aK<3V5n+Sfu|;50KuyeWWYiO8fhe} z2^Zw5>#n@+dMgm7Xyar>V=k4VUPV3^-H}M*g<^n-w#J%8eg1v}1+$}my6LvtvWkKO zj56wN3K*nnE=Co!T5AFj%(`v@CtM)oy!6)lE3gwtfKij-rk2#0$PP-#vV~3uAOd3o zOh5xoVkDac21u#{rOgVEtqK%yO2Nh)cbuuED1d7cq-~a>|bx;BZwHDCs z3bd{p@4Ol0tn#4=$uQeY^Sd|8*bE0(YqT%FVlL`0!U^Zq zKy*qkjo0Ff8*udm8+fxp)_rh2!q?4;T>{ydcI^4a{%60e_6QWTodVn{V6dv&AJqNs z>#*0Fw>Q1!dhZ#V0F4m<2mZyV?;>Lga9#t*Qf9LJBr<^lk#EraEWhZGDbhR9{c&S<65u1b6pLz-vtO=07cmhJ1utpR(D;Z&n|VE0>wkg zIb@*#Z$wW77^oQI7zZ}iWlwvY;-1JRI6?8fjeIJoz^hiJu63oX0z9jk-AW)Y8HF%s zE`x+0^3{!)?M@poat*(nBC?7UjcPVbjRc&>L�wB%x@C2q-|Y=@1EQP5U0{LZ^f7 zQSgb_aexU>mjae)gKl`c+XzWeLT}IqND^SxfCS!!AXN3Ge#3$iYYs$_H%Sh1Jmf(1 zh&Y{2Vc?FfyW<@xKqMt%kBK;N;sNZa$3ot*0^yP(2~76EldY^}FUz6|M5vM3O+Z&C z?Aby7@T03SgaHA-Mw0?i0Ep@9BB)Gb0Rk{AQ}9g_)1cmwu1A6d`sZSQ?3@lp)`GN| zP6Veq*STg^OG&1HlJHXB`j#o96y|9U9n)MNqB#N#bc~j0>sSs{cd~JDvytF*CJ8#Q mGi-{0oI5)~CfBL6XS(y9@QkNC=Sk0c+Vh_H%qM6<0027&Al7UE literal 0 HcmV?d00001 diff --git a/web/images/apache_pbw.png b/web/images/apache_pbw.png new file mode 100644 index 0000000000000000000000000000000000000000..b8fba2afffbba96cb75ea23fec130f93dda4b494 GIT binary patch literal 4181 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 XDaW48P4{ixlV65+q_VA1z`_3l9+2ak literal 0 HcmV?d00001 diff --git a/web/images/debian-logo.png b/web/images/debian-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb4e62a079eab8474211558e0fc3b098a2f6d06 GIT binary patch literal 3366 zcmV+>4cYREP)3-o)>5Gf-rDIG^tTq5O?a$EOH?3H^wl^{}x6xZ~WwPw- zvi~W?A2Cr$~K(rLI}bd@u!~#HhGtvT#Ag03=myldVNZ( zS1&JLz;wFP#8?z2PW%~4r9eDiixDHTF>6*Ju3WKT*RE9{3c`#TE7|hpeTm~1V!?tB zk(#;?Kn~{5zkt-#cmU@xVZu?2AMcO7dvC#L3}-rBHKnGOL#M07!i7DtcJ15f-hCI= zt?PsQ{QKCucP7(n^&|)!;^V)AzkhpVWz~4q_tjVZXyCvC^ytwZTJ0t%6g3D6`YUeV z4rN(cHWGv!5ba|+-8RP*MT@{{H2o~;mWLsZmV)!eydilCr};(-JGL{VHJ zS}eOMDXD}wPG}Xty?cK}JfDlCq;FAE(*T=IiwP5QF@AhEtXlOa?A%#`AAZ;a#wxLN z=}W|MQ!!-7YQ)6_0ayc~zhKIg0MylGV&1&t2ncA8<;!Pa{P=DdI@ACFh>Hut^5wm; zV@Cyuw<D`yoDlCUSGlNKVcG0K~_Chq^jD-hY1v`u6SURo{@17jXIV0_b#SuypB1 zu-PsmCZ;>=_9-L?YOGq-7eqO(Qxq+LI}CH?oDhqO20QvxzP>3crLt%HPe1L>R;}vi z`{R!tRh>HVs!p9w1Autw(95F5@^2D^i7f&g6Vn~@=LbTsuf?QE(^+guA=wQGA2h2q$;J78=z7A)wAqeo3xvSbiOj+}`vzbt3x&x@Eb<3;%UE1}VB zM~4my%$^%0H9K- z4nwJ&&a$#>P284Ns|PTOI4(i7SUv#&#K!KV`ub7KXuRcB;VoMxGp+WtTc0S}!B_wQ zz}GiG_KUShO1gqgn_fj&m>))uo`=lLRH)S|EMEK%0D#RVAuY`Wlj#!}3@-z?_INXN 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 IM6N<$f|Yf6F8}}l literal 0 HcmV?d00001 diff --git a/web/images/logoDev.png b/web/images/logoDev.png new file mode 100644 index 0000000000000000000000000000000000000000..1abcbea63ae3cd46cb20cb8ee8bc7b2b509c6de4 GIT binary patch literal 3295 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 literal 0 HcmV?d00001 diff --git a/web/images/logoDev.xcf b/web/images/logoDev.xcf new file mode 100644 index 0000000000000000000000000000000000000000..8ac3a9404d7b775c4d123b22ea7bbb58e70f1456 GIT binary patch literal 149953 zcmdSCcYIyN(Z{`4)v{%|cT1L4uH@b;7%(jmAPEo>2rUFK7%L$&E6|Zggo!(dH;J2M>DfKJG(o(=j?2my(i3_ zcY5WbW9L-PnS09d&bhos|A0EzizkubPamExyIH=t|$liOLdHgX8jz6w);oJo$R{mh$1Ad~Ip2j+N-Z3W}Kjwrp=N_jp zxD&2^{({A)9A7#Av{U9DH==9(oD+^c?Ud8btgJUM=FAg*bxh^>vE%LE_aGCpQ6otD ztM5sgi?96eh>|XvfBG@U&OP;n$_cr=2wePqf!VMzXPr8CLFL?2k3I4D`AUDG-gR|jzK=p}*K;O^{ zj$gE3%qhn#KK@LCtf3FDpLfieC!ckCW!26e*=1*Rd1~eSxl4|pbwt&~DbvSKo_<8t zF4XaeaXXJw+%7wh%d%FX&^f1_x}dUZ_Nm7mLw7mgv{O&Z1&)!3${EvgUBRaJ&yNd>cpu#$}P?lkDq(Oi3=*HO`P62+&Wx)O-`Ik zRp_r)52-l&FMoqa+WQU7RM4A#bqCJ_JWukx+?l875_;5)JooZE&hskIM?A{ zdFDH}WV>^zJ)OJYTIVh~+PP~F<{|D{;;wCW?)tZ#yX8(Ee?o^W4GnFwYA-@A7=b)9Mljci|bxQ_nM< zXCIzJc~0b6#IuU$YMwiI9_D$0=Utw!cv@ZJr(Jjk^3?N8=h=tnP@WTc7V)g&xtiw= zo`-o};CYwlE1p*RRTrLtJoP-&dG_Hsl;=dAMLer`u2$b`==uNir{GD~(DC_yt55Oa zF1++Sx3h~@xm{eeGSw|L!9~rfid2Qb@YIm+1A|?3U8*VtXzm1-ccf~FuSpGZ(XUh0 zfN-UFA)Ae?1=Z6|4s_8ashSjEg$K>w1CqoiQv<|W3rIBUZ?xQqaJfK;#Um2riuj)!!3C|>;E9ts!#w}&Fc|Lr0B`1>9eCmdNPMb}Hwb;)i?%9Nx` zNy^mzpwcnPswBnAK5%vi)tlYe#S zkN4hX${3h>l@{f>au@EJj(fx#GTS$;|NNtOUi)!Klmv1~gG%y$~h^t_aE(6e;3h(l;-?JW${J_KAH+XnNXfRqB zSHm7%0T}4Q;(I+D_;(M-eCXj`8$CQaG8ml`*T5cK2^iqQlKVUy@(&Nkf9&Btn+!(B z#wQ&S2e)kHvJL(?)h$PGr+uvDv=7$y&cnMOe)>n)Rkh4EKmB-=8c7Kc$l zO=iSxVJ3z%-YHf=;#qMN=uZ?klH*+eWTG~ctgTJf=G7*WG)A(mHpvShn(*p6 zYA`4n_<#hFb;+R>wJKbd+9O$58&#_g$)eh@W;`_*o6J*?F%-CQ$uy#Ck}Cf$s!cNA z#|D!zD8?rXYPVO{Ro9GilOU%h!`fVn!Tm)wc0hr8s?$*4BjP_SE4E%5DG zr~K+Ld$(#U2K4GylyGDDo_!p)Zu#cRPu~02Kc0H{Pq$rv#rX{jPCWA9eRrKQs%miG zvXa6)tm{7UhVw%

    7Jn-sUUtpE3u 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 ZjStQ>J`rGV`a}FL=-+1}bbLjG`wtGv)$jlS literal 0 HcmV?d00001 diff --git a/web/images/noavatar.png b/web/images/noavatar.png new file mode 100644 index 0000000000000000000000000000000000000000..22c5049c1ba0064f1fc93f1e066e3f70d96a69ba GIT binary patch literal 5491 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 g2zIr&z^9ndhabD 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 V@=O2qLc;Pq#18roWTaQq{{mjF5|jV{ literal 0 HcmV?d00001 diff --git a/web/images/pgsql.png b/web/images/pgsql.png new file mode 100644 index 0000000000000000000000000000000000000000..3da83f15913afe0ed053f0b7c77fba9e07b8f37f GIT binary patch literal 2632 zcmV-O3b*x%P)wPu#3E3!wW0!oOO!CrV@Mz*gyfBPIH!NS6hgrmDd(?y*W35p@9p#L zZ+~|S&SGt;Ok7yLb77DUbFAA@Z^^zwX*5ym0z$ zqn-d*x@r$&hj#h?fV9?P>hqsXKYaA)^s1;q&yKBWotsU{^N7V_q>>KFWD3{y0WhS2 z5CYQ@ghF8~TacaIiiYD+wrxA0tE&%-p~daCoZlt#%c(bxS+Q|nls=szEd#Wo{Ls|r z=db>=)?wZKy!N8{NG%5|>Zq-$L6{k6t&!=(AcX~hQVJmj;NdHUZCONPQF2;kkzbHQ zVTT+V>Y{wHay`RJir#x^+PJc1pKj%fVa3e@dT05z>zn*xdmJ}~PJl;HXO!To{$awh>9XdaLd0$Wj3)bi1w44;@I zd3EU~F6+~dcOM#yW7y1DvW2Cqw{t8G$wU&3k5=iLP+FmVFiZobJ(Oh-3Bv2zIi{&6p*NAOldYZjvh4LLr1EJ1az9c7(iE0i>7UctY^?_9|w)^$7>-5(sHy+cu8>?HN4{kPreX1WGw5 z9}o)cAn|yLJ@E?sRFrr;LCQ06QZ8}j5N$}(5ZBbz*K;`L(NG`92n4~kP^Q3j4Ki(u zgy-RYN5}eZ#dCd**VZ!iH+Ny0CgDhk4dojcFk}!N3JY1bU_Qf#kL1YFN>a%r*WPdo zJqGpT;I2)~df`PxelfiUj6_JgMVvbgkklGO8YkMpx^LDKtv*26{m=2{qE9)bO-gSn zW6Dp4a$#{NcG{(^s5pSk>cNzW0~tQ7Hxr&(fa~~V4!NF%)2A?`v>$`6d4vo@5O*{n zFf{mQNR&KtV@(s(uuSH@Jd+Kv*34eI4%^NkHz?SBB+5m_`3$-9Wh$yG$qd-!W`%fX z#b!o7GM@zxjz>m-cz_YpUghIeaW+3qej$QTFI;K7MivQR&jkkUa7FBJ{B;ln@9ZP|8Qi zbe3A2p+GP|B9Wx9OII)gCupdAk4d8jQob*Wsnep@w0xZuATpTv*xU5&*%`-i2#3Q6 zL*Og*oeoT%-uq1qL!&Vf7N}&BBqs@Jno!)ikd-qg^Wv{Y^Y#N1P|9txhsV6%Phi}j zE?m_sj1(p#26o2|=VM75(TGS0aYnHWlm1t>1~~`Pg>a7mXU!m&wn*PgPAFlPHq4G1SQDJ z&EuaRen6W@Q$>f{wCQ?+4VVSs&`<<@g3_2tm z4ZHv}1?@ZW&VohUIdLS~i<1@fdHdg+S@O)!_}e3sI9yRlJn5VSBuumw;-$rFC=gY2 zY8N8Eb`_t@eFzZU((Pi6@Z?OfQ9Q{9F-$7A@@dX`xH=NJxY8`t;|X zX%Dkv$x`ZStNGK@kMrzb7xT*UUCg`xO3L>fX<|EF48!E;md_YrZ(;51HyHH690p%A z4M!Pi)g_&sGby#%5*Mts=Duma<*6s86R;Eo9osSE{#$8CB>C*k01wW5<>ZEe3}iIM zqJ{6%;lk@Fy?!i-goEccmT2P%=x-^rQvf-Rmv(~E0K-6Y(n$%^V)WQC1Pl+yRrDJ$ zn3U`D)!KE0EYZZWx)c|+<@050=r-&IlAe#iKnM-^NFmevN*7P*<~dZ<+S`#zdT0zB z*ZCjO5GdbADFqr_*THdJGF!ExZC*|j;3h-+btfmkGXdK|2${}F<59Vui)C6g)F9rKEI%QTUAk6Pr?y6u11)RQfUe}!*^QScAd!2$pocQ!sJ*~F>%ZgN=J<+ z>G+^Ey0M~st;h%lktXckQ^}A4#rHLPWN$7hr+1&uMGwzfwqr}OF5~>-4p5(Q)V-q8b!^XT6*hp_OlEr(E0V@goIz;VFSKCzg`KNc@U z+96~hgWjbhXh=aK>40bAnI?NH53z55oZj8Cxax<4C*L%x*W4D5V?J8Bj*%CYux?lV zrSE>cVaDfQ?-*#A0g76ibT9D9%gG{W8~DCQ+*fE{;<^egETSooyOuFllR{*(wF zt4VfoAmTNNo@5-jgaG%Eh#$SEe$MzEUT)50-0na9NFZX}oZUQk{HQ)@dJ-KScI@A` zU;X->f%e9&-2ip`9rXSE9slH4wF0lxVR@kVurnZpkE#^I6pWhcLgIA`%4#P^7`0Wi7Awk$J| z%rid9n_^>YYvbU2-TP8_8Un}d0~2K-zCt{gf;rd48;AK{FxaiJAEm2rf;4$?Kp(BG zweMfwq0a?HG9s%$Vy%?{O^*tJa0An}>%x`0=88B0cBbh<4@&_wO~l zYKh^4hi3u#=X~r{(*vg+oxQ1Ktj%Rh^V4QXv&W~;oV7TA=^B>gMRl?{fHqy`9e+A2^_=gVgx|{Q(AvUd8BQwqfSc+B&)hhb>&Gq~m+dX^3*feEHd8V0=$jYKV=F$Tx*UbZN$dPEtJT<*K9?M}U-hyDh=h(YOD zc{uJiXhF;%{tL0}t?%q(hQfe5ODG*Z?eiWEUwWv(jn}s{&iGlOP+BPTcJwL=4eWV) z$?xE|#o*qXEMwR`}d8b4fa>^}QH_CR2PW^#t;ncM{lXLvX{TfgLrKzj6(@gl{Mf4#PwZu!B;Tc!eKCfgmrQ|4#~&f140*H0{~mImUjfi=1)J*3{G zuAVNiNY4&2r#nI1GT zGCE*rsDJeIRVP}*OV!(F?U5HwpFHs%n^$Ae@#*z_-QyEaU$3Z;s+Fa=`=j04x*zqA z-Gk3ses-&hWqe%j;`ov?5t}Z$j!>+7B{D0G#oEkuWK{eaHY`&Tv#NH+2C}hN9=Ry%ms3kWO!VT zKYij9kvBVb9(~00Lf#np3mdD87mkCu{q!}A9B_#xJ}idL4mTb1193uWV6<(Y1nf3M zYiaD)F=ov=?AAqTUb#d4%;vNeoZF!-SZrdti6TXJzb3{|R||FDf49j#493t9gZa_! zq1(6m2liZ^HNjjt_wQIZ!{c22aVE*w4sIN`SI2M{P4Sm2 z77$xEa++p*kq{P{a@ALO$PfjJABFCB*V&6g>1gYqkf>Q*EnQlTzJ}gDxBfp`pEW!F z(~PS>kI~a`@A(g_(`Sw!`VAIG zKNH8$(?M-Rz1|znLmxPKXfGN-vpO1PI7y-5evO#I&#cYOwopb^r103}GZC2>3{bX! z*_)sgD#h|>lnzurs~xS(uWvKg-cuO5>&k`GYH+;-jV_bJV_22}d|e2RWA-H9&7hW6 zv^nn6L7}uSjSHF*OHc0889!op@f_q#zk#7!paCu{G8yMkY6{&jj{Y$<;~*-Q%gXox z1aiM$?ExD%@nKDiXMa9tc@7%7m5WODKhtCexkdDzRHh+V8T=b}fwxbz$#=K!iIVDm z7hU`3tLLnsUrfJQH`MrwQ+OmjQMZ8z{j#z*oo)z-DSQVAA4=!wW7EB{QvGiS>@=*; zgD@OAa`@}@RS0kqF|-W*>{xxsX>bw^0Jmb-rLT_Pk2S0vfie@TpFh2Fc`LX`gCNK< zdsijk-s)&dqIDri=l}r(F5OQW)S@U1OG9?rT!P?FK%*US&5Rn1No0f@4xRv(q4p^v z^e{SlA*H*)b7u8Xm0@;b;+tkl@YNMj}>*#7^rx>6#jT@=E zU|?qTwTYcEoO0H8cc7tBr^KDzFh_Z%bVRA9{>ZM2StQ`?!{`)qHSXlO%DSI0#9 zxT*zXVSn|i#o1G84n`1|c^S@+kruA;&{%iBHX6gKwbqg(e+%6-tD~uFcl){9u9G?j z=Ru}zQDYPimX?JEu3tLD%~a<|X5Es7o=`PWsoH#fO;eW@9ou&*bB4l8)oFNR!y z2%VztfgDErP|y6-{d*Z-e0#~_+^H@4jIOysucTz;3T;qBchik43vNVLjkI|01{_j* z?qq}cf&CwUebf%Dfa~=D({q|;WUJ=b8M&My`|tJj4;y)BTk4_D4)FUS$Pr*y+%!#1xB#;!myiUdl_tECyyUH zx^EW?VyY8{&K|+hj8xzjvHZO{Zlp)9I_&!n*IHS*Qa03qWzhJ0qkCY(^G;-JzX_(EAx*}9qBSVFN8MhEkQYyWOHXIG-bwX0SZXV04*-TU`6K=p7CAt*zSfE&@w zY#vWi_?}9&7qN{EPBHFSnR~mC@Q!v@FJ3-pad79?iHH=$$B3J%z=H-hKH>4KtXyGH z`MN4jmitd-LwyrfM@>Shu0#UP-sZBExxubI?uZ1y^iLuX`KJz<5^f~0vbfTs(vp$_ zi6Ebw>azF5xjh<=VN?$n3K{2k#r*IOdk*KRKwCA`7h+*zYDO{m@ok8!`GWKjjAS7TzIam#LxV2%pV|$NSkOSgbxw$!68B7M9mY5J5 z?B`ChJ$HEjt{)Dabe4fFYYk8^3P4r0UC=p4Q;dP>amy>V_BcENYj1t-lqpJckH$f} z3j`Mt5N<_$j#%plJLySPVw`uHr~9=ddf)%g&hNh4{?+y!=;K%yQn+g(M+LXqeW24= z8wH~$s;6S+b@Q)k3$im(IHgiuy^A-J<+EU4zc!56iCCLJ{0HLA!c2F2!_ZR|XkozB zzp5L8S!r28ZgOZCGHf{}m75;k@Derzw_!stSm{&O%oK1~@qs}>fuV`)cq+GIS5)&j zuu%XTf=V!>G}ku3d8=P+X8MFPvZmuU$HCz=ohUKFq~6Ffon8Nn^xCh28M? z+vfKqATTf_DuI#8%}D)Bu#OIR93Jc7 zh{fXZPE^l;Xm(z9g8L=gz$p;EseZ(Cf{R~jJ}bbRLLp+YI6R&}Ac9}uhxh?;9`A@H zI$aOT<}jVkdGZiVAc3D3Atv12lk(DhC{UMH6q~y!YlBO?30=wXLGRw(GFXJ zeqVeVCx#5V`6WChCNJr{-4NnAD7obnd`^}>jzstd+`y5s;dzN?BGeth05K>h#u0}j z61Ia|1dtoCLej}zz`QAU%8-!pL?U4)VVQ{a6fjSu!pm}kyut+s?D&rG3)a0%bSxZR zl@JvD@z*wluO<(snFWK(3sRSu$(upecp?dC_?++(o`?j}wcz1#@6#b_30JS0w|5e* zVnJ2{iFYI-iGU=$u}z#VPPCEk7aqJnBmAi;;=?MM!`o;9x*Ii3`?#7h}I zAgW+&Q8i!Y;s~bj839RNunnqORNag7a$c9|k-FT7$(Q#}zEQ2*6$L}TI|6g@cn~s2 zJPBAxB-!Hv#S^P5(|j)vcQ>cga0Y6OCoF6km|S?PQa!z?UELgZHN9-zV5in6Zp+jpiOjPte_X!~_?JyNI8c%D!y8St{`ZcGaS)h(-rag8BdHH$&8zz+&A1jc$lCVSynMj<@#uBkaJefiu;v%1I?0zA!b9 z@P;ngqAi~%kF)3k-&i==37~&1L*}3egeNH4?v#FiXLc3woRg6vw3APs4q@-CaG`vrA3!C541Yi7TG4 zjj)7^9PuP!@vz7NhQm9$wdWCt4)m^1L#|)n#1^H_VF`SZ!ahdi1S!0IUY(1pueSqS z6=sQ8-{_`RSFF8QzCFTkt1?OijV~(1MJk+OjV%!E#htZn)vfuknvnqHb(Ht@1mdo> z-9Ux={|YWj$&qxvsK_O-*cGT-B-$0tR?#~;hU2gRdx8&nT60^{?C0n(bI2mtn+nWy zKD}PJfa3`Y1F^O4cpy1WyjD`^eoas=SK1N@1Z?(A=aAF}D$eiOU)=+}e&y8qK+Q2N zI=rDil3h^&g+zAB7_@=It4*U#1`^kd__G;KLa%*;Pp3VjFpf4BpK;b`)CY zHn;`P{*@Z^zcHai=|ygb@mjHO*joto+R3a8n#+Da3 z6C6BlrrATSvqVD7h_I@csTmd&;O9s6aHFn=0jgv21!7sbwf{|9umC&IM*Xn(uqiS$ z8cCWX*Uj~GV(`(?f!^L;p6@ZJ4p=Fc6{KrC_99_%L{d?2v|XL_3h*UVhb2c&FL`L% zp0c7l9Jks!><{gH3QDN2=H67_quU<``KW7Q6H}{`7ASXf8|=v5 zWA1yMp5{8YWZ6SA@dVdqwk0;G{mDVyQ0i|vwK|zXnY42v-=ihJW??)DpEZ}}0IF!t zYjk05?g8rybU=VQrQaLr6rU=9lPf5$a?~3fOEoU9&EdBXcct4wZH@%rHj4x3PkwNW zgiGIMY654*v)8$j(kkK)hK5H>T+&ksI%yoWl_acRyD8o?A|@Oz&|5g!7Ou2fkz3K6 zjz4+ys%?6n1Jp;tMKzivB*sMs2mO{4QsUEuVu?&%P*Pe}QP)skT~l9MRT7Y#?*N@i zNs((L#zaMg1_KPHn2T8uSZb#WC<$p?iByd#%PVVYt16Vmh0*|qNIg9gS&*jBjE{*7 zfh)V0yW4e&IURCJY*0onU-WOBEIgt}&5@l;sHa%*(GhCS)5D8ueOdxJl^>Cv#udmF zz|3Fu$>ZH?)ziZ}_g!(KMQ`Zy_VIEuzd8>#I(^kd*YuoBQBiS8NmXT4^}3mgWJ;$i zg^ah49??yRONt5$xe?&w3*2dWv=Bf&N<=Q!IfIi2x&UQa`6iW5kd%^%UinkjSDA4! zk>R1i{(vK&JI+BU)SW;ki4c{|kdpn)CqEy08 zU~wSbk3tD$WC;{SrO46;g#|LHOeD#R4ol5RV#^Xq? zJ^>+N5y*(Az)4hh@-^!#7jZYP$Fkv8_#W&9?yGx&Yz|9Kr-wP?E?HV$v^sBLX=Upg z5g(QjpI4~v1*Tvx@KD_gJgStky-yE!R+bf))Kn53{L@8+Phc-Fv)K!%mhO*_+?rg5 zy}-D-7kH*xZSC)@E|$sU(!#o~YQY^9Yz1DyR^ZX7bmBo}TT^*~L?RW*Dw;}jn{IhZ zdS`%%ZJ-sndkaixqD9o&Qk2ck%i&5C;3;BWUUpsvEiNs;rm3fT40ZzdVJGkq$o5s$ z6iV~?1?3IR-8Tn^`jP#!1A_zoH+wtkizVEwY$2aM2AOZfhSH?5vaKr1Ghno@`Om? zET6|0aPvVLNJ^_a2Ks9G2}y!Q5WXkVh?iyjg3jTtvO>9(&jDgkRD={Eg-=9c@J=Ae z&zDGxs(J>Rd2~)K;x@?Pr2)j8T--6-St#Zs`AETM{FeegSTu_|hw4&T_Yil0%<@!e z_Q+7Zfd37DQN-m`54X`6lZaJNZf`2&!$U=RQW1YUe~Fhb$f+7_U>3nX;7y-cc&kjn z=K^RcA85|4y_K6V4(~h=b&QJgfjv9<%RG*Bw1Qp(FOP7C?+T#N;Ic?4n&?jyz{>-Y zo73eS0aU)kHZkZnj!NAmsB4vTJAGwC2;qY6)>!$=ol?qoQ0H4@&TIgn8Mr+b`dC3Ass7 z;?+ogMM>}M^Iu*LO1M1!Kln)TLQc)d!rSL1QVCc6ke(4iX<2vo)YGNawFi9#T#;A= zJSY?c_w)Ed2~Qvth;#D_x@T8b7TWnj5Q-$YR6PTjvZuRibo|lM+qY{=ce~0!1Re-Q za;a1V<|`H}ss<;2S$@5AuOTyEAQFjrYVNt3>uK%0KXvQppP#>e^A@xMKd-)c{OIAs zna9sxt*BJLEG#@3ZwI9-k&1!7bxv(&Pjge-?K?mJeD~hO#LU#ACv)>J=bk;Cd;aLj zv&q{7Ev1rtp+pFbmTY2UBSK|)Pg_U(?FSPRQxERkY-wumXsT_ll5qINq6BX;#Va_Y zR3Sx5m&78WaMR2lz?Jp1cC_ERH`{&V3YK`~_!-y<9K2*>WqQhz5*X%dd%`SCE>`>o z8`;F3#+(c+Zft3;;QN~yM^tpSv{lsgwly}jHFeNU%>@b(C6O$EB z#dKC$T$@;@i1({67e@G%)x9k@Lp_w=rgu5@}7N$xIeq z*1MySF9Kz-o?>dQue;YTqBcE=@d4vC|L4?XIvsqy!vGXLg~=YNO-xFXckYn$K)U`) zRaEzN^mxV8vY9~J5NWIRpE;tUS6X|!gAW}$G4u3=$KO;2|ZHKIN< z8Bh!Kgocssp{}9oM4%AKn5C5uHI4S?G81nFnUzS^)xio|92V8pc6E0J2GnN(vli)b z9rOM2JA-${i2!>-&t2%9X}p=8l=$qBdy!h9KwX&&kn3#eOd_M z#6T{oVvLnpKA6tPeDTjzg?f7HoLXOJW2e}vKLcRn%-H6Zq?9yP>CZ7q3`SDzL_$K% z2s6H+^m~O^sNnNu@70Ox>$_Syn@(2cv4MiO%($j@I9QR+B*37|(%-UT>wA-maWpTe2@dy4dTxVGLf;&39cbR}`9 z4tnyPbUGfqolWJ=#}*FLZ-wZ~K?(h;Z+ci*SKrmv-YPYm$O3AZv|BaIBpSPFG(v4B zjWtmv>o0t~Cup4$Y}h$7!mFwM(&#LDcXJ9oA#1D{YM-UCc=zji?j;!t zC1R08BoxTkr#C&qtEug7Z)@oy_>RXWF_}r?d)cgH&K#Wu^I(>llF<9&Ucd2;!g8<{ zg2nJx4yXfMqj=wAPI3|;o5mEey{!pJYBNDT^JiasnD`K#L~_AaeS-S>j*hmLmVSLs z7b7}}5ifiGNi|B4|)^&7DzN&vWRE1m3et z|8Q8lIgz8zPiA6D^GN69)8VR2P3n%DOQZ27AqnAm{Jy7%hk^ZQ9(9TyY<$872w z7B)6?!ud5fv=9#r-ewz@byqbG4)>NNKn{FI+huON|8IJsg<`PY{+3hwrMaQ5jIt{i;xT3F2>oH}l6m%YxVFhq67 z3yNi8KJT|_Hpr`Q>g;T5X$D+%72ML4*Vk2-2dC7k?WAWE3iae7u+x$P4*HXm%mekl z+|OxjZtZMqMmE1~sH*`R*==RW(qD=TLg@8zAkmi7s+p&XWSgHT0%1WWy8wW1yK~Bb zTeh_<1BEqJmE~nfHCPxO(Gdqc^Cp?yZX8zlG$<|i@VfUVEV(L6Km%6YpT_gLl#dLh96Si8-GxB+`393lYlKe z=oDqyNjC}+wXiP$+r^QRTz*AOeKqJ?D#3PAsVpfeF1xYsjJ4*0m@=_K2KMoV5&p{4qzV1T!irQI;u7%8Sz3vhtFG0=YsV;fd1Xk}{Q}2*fyS3qX6I zn(kC`vqd8Cs8Z_{Wbv`e@}3AAa}&VmD&>({H}C%ual(`bhP9kd@~BkL}<5ky|Jpmt z!a3DRZ*jM-3;ye><*x zcvDVne<7AX`O81IZ~rot{Q>)3CVA&} + + + CodeKicker.BBCode + + + +

    + This class is useful for creating a custom parser. You can customize which tags are available + and how they are translated to HTML. + In order to use this library, we require a link to http://codekicker.de/ from you. Licensed unter the Creative Commons Attribution 3.0 Licence: http://creativecommons.org/licenses/by/3.0/. + + + + + Every syntax error throws a BBCodeParsingException. + + + + + Syntax errors with obvious meaning will be corrected automatically. + + + + + The parser will never throw an exception. Invalid tags like "array[0]" will be interpreted as text. + + + + + Transforms the given BBCode into safe HTML with the default configuration from http://codekicker.de + This method is thread safe. + In order to use this library, we require a link to http://codekicker.de/ from you. Licensed unter the Creative Commons Attribution 3.0 Licence: http://creativecommons.org/licenses/by/3.0/. + + A non-null string of valid BBCode. + + + + + Encodes an arbitrary string to be valid BBCode. Example: "[b]" => "\[b\]". The resulting string is safe against + BBCode-Injection attacks. + In order to use this library, we require a link to http://codekicker.de/ from you. Licensed unter the Creative Commons Attribution 3.0 Licence: http://creativecommons.org/licenses/by/3.0/. + + + + + Decodes a string of BBCode that only contains text (no tags). Example: "\[b\]" => "[b]". This is the reverse + oepration of EscapeText. + In order to use this library, we require a link to http://codekicker.de/ from you. Licensed unter the Creative Commons Attribution 3.0 Licence: http://creativecommons.org/licenses/by/3.0/. + + + + diff --git a/web/lib/CodeKicker.BBCode.dll b/web/lib/CodeKicker.BBCode.dll new file mode 100644 index 0000000000000000000000000000000000000000..99a7dbb6fef028ac1ec7f971407b609210c6dda8 GIT binary patch literal 38400 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 literal 0 HcmV?d00001 diff --git a/web/lib/it-IT/CodeKicker.BBCode.resources.dll b/web/lib/it-IT/CodeKicker.BBCode.resources.dll new file mode 100644 index 0000000000000000000000000000000000000000..9615c2f65d347e3445fd6074cce6b1916bf4bc10 GIT binary patch literal 5632 zcmeHLUu+yl8UHqMQ>RIz7SgDJNSW9!CDhq-YMcBaDQDj~t%;pnVb)r&-3g%#!0gzE%Bs6|l<6$io#ME>NAsD&kI-+%vo15MV238E=$BmI8<`zKOq z@6v`nTdZE9`>?_<+OvDn3A|an+zEU(Bzj|H^ye=v;l(<)jg3ybO}#NQO%PqORis?Z zjBZ&Bm}!?nSkBr?`XLYv=n`<4*LJ)eElV`sF*U{m3_Z3EpyuVQ1qj9{?LDp5fY zoyUB=?F+#D&5if3GyQXT{h3CjWz9Y%qcB#kj9Q~p(kV$bC~A=#D&H#(iZfD0UKkvG z+#cd*P~>7?$4VXzWUQ6r4~jxu^gZ{uY|MspGB{d1aKIULM?by)(C~;HI(VpmwXitQ zUQMRbXQXDoG-HYiV|o5t_}ibKe+yx_lfwgz=;^@#A<}tn(AY&kpVV!*P$R&p~Ng6}1Nnxc3 z7_V^KK0%Q|sbe8WRUj*R3;=r?m=PY20;*6R;4*+QchWpa^R|o{$#6 zq(naf>MlkNFl`GjwZ#7c2oKLfScMo(1Hjagp&o^myE=i>#y%ISCz@UW!V2n>aD+6% zO7vX-#c53D@UlX|8VYmtY+s3#2>cTO*4{~9Xs05s4qX#fMrj;9Is(MO z=<5D!wsirhuA=~#N{YU7ed6txL>w`^E|u^fm67Yzr6_r#?|h#C%9r|VF;Ol{tz$<8 zvWI;=xT!CuXYR~tsTwx0$8C-FMTtit~oNl5StItEzN4qqIAKa=JN1?#! zQ!v-5$v{KdqfJD(#301VF`i~c7}bmFVNjC7NldCM>B-n3 z@1WVY9bHH=@{mPrgys0m=ft7nP5(b@h=_gJu|)vS)|mE~_qlsGaSmSSH% zL1|v5R#Gkd($z@NG=^BL75&Dnr+qorJbaRDSBI(v%;Rh+ug(N*l$0_T*6L2sSPdvB zh2fGEj(hH$RQC8dPjEw~S5V3K=?-x6^uEd2H87@e z2%QS<*4*E3yylj_ zmH&%>bNROqg*{KocY1_nZQEhdgR9g*C9`bN((|UILRE#^QzVA$^J;Zp@^N+8xyT=) zs&)NvCgZ})xy0s@%-CX53s9oaP(b$^0w=NP_Rg?9l+d{HaEp19z)kS&P*pOxHkfaeDK;{o$-um=7Tr6V)FNhYXVc3cvw+9K zEU)U)nkoTY%!MlN`_qmWBxg!Wn*)&B?MFyt&FJpvERzo(PO9h*m6D7*w8lCkaqW0E z3x9Rg&s#T*VD${m&_(nUbPA(MRN5ynpG1Ewsk-T{p7;Ng^Qm!n)H#mYW!vjpu za=8XnW{(tfyX!u0p30K z>2YIK>eJ4hBJ6c<2d^_me=f(ng@eWTbQCDPtW+pT|2hzu$>zTCh<7u=<&r(+w*DOv*l~`T8fY8%#wJ>(Ae*h@)0xCsY~q2vmgvZm zb4Hisbj%xF*kV3&yaQ}Q_fM*1Zv-kJ-WdU3rE*x>VXSm(&Nj9sxGVVEm??NRV|>-t zH^NF0)?}J;_!K5_%KLv3G`t`DV~F=ZjYXdEnWR=O_}{U2=Qzll7%xB$$8Zc!>W(N| z4}YQ&6Wc3!bVqo1e506wePi%E?^?}d6wWUnL}#4yVRv_WKqUV&S~_%hs`sH*|6dRM E7r}tB!T, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-12-06 23:46+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: Controllers/HomeController.cs:51 +msgid "Bienvenue" +msgstr "" + +#: Controllers/HomeController.cs:52 +msgid "Vous etes au bon endroit" +msgstr "" diff --git a/web/sourcefiles b/web/sourcefiles new file mode 100644 index 00000000..72140257 --- /dev/null +++ b/web/sourcefiles @@ -0,0 +1,36 @@ +./Test/TestProject.cs +./Providers/BlogProvidersConfigurationCollection.cs +./Providers/BlogProvider.cs +./Providers/BlogHelper.cs +./Providers/BlogEntry.cs +./Providers/BlogEntryCollection.cs +./Providers/BlogProvidersConfigurationSection.cs +./Providers/NpgsqlBlogProvider.cs +./Providers/BlogProviderConfigurationElement.cs +./Providers/NpgsqlProfileProvider.cs +./Providers/FindBlogEntryFlags.cs +./Controllers/AccountController.cs +./Controllers/HomeController.cs +./Controllers/WorkFlowController.cs +./Controllers/BlogController.cs +./Security/RegisterViewPage.cs +./Security/NpgsqlMembershipProvider.cs +./Security/NpgsqlRoleProvider.cs +./Security/LoginViewPage.cs +./Security/PasswordConfirmationAttribute.cs +./Security/ChangePasswordViewPage.cs +./Security/DataModel/ChangePasswordModel.cs +./Security/DataModel/RegisterViewModel.cs +./Security/DataModel/LoginModel.cs +./Security/DataModel/NewAdminModel.cs +./Security/AdminViewPage.cs +./Security/UserListViewPage.cs +./DataModel/NewProjectView.cs +./DataModel/ProfileModel.cs +./DataModel/NewProjectModel.cs +./DataModel/BlogEntryModel.cs +./DataModel/BlogEditView.cs +./DataModel/NpgsqlContentProvider.cs +./DataModel/ContentProviders.cs +./DataModel/IContentProvider.cs +./Global.asax.cs diff --git a/web/style.css b/web/style.css new file mode 100644 index 00000000..2b4e2c9f --- /dev/null +++ b/web/style.css @@ -0,0 +1,149 @@ + +body { + background: black; + background-image: url('/images/Banner.png'); + background-repeat: no-repeat; + color: #D0FFD0; + margin:1em; + padding:1em; + font-family: 'Dancing Script', cursive; + line-height:135%; +} + +video,img { + max-width:100%; + max-height:75%; + padding:.2em; + margin:0; + position:relative; + top:.7em; + } + +#login { + position: fixed; + right:3px; + font-size:x-small; + background-color:rgba(0,0,0,0.8); + color:rgb(0,254,0); +} + +#login a { + background-color:rgba(0,0,64,0.8); + } + +a { + text-decoration: none; + color: #B0B080; + right:2px; + padding: 2px; + border-radius:5px; + border-style: dotted; + border-width: .2px; + background-color:rgba(0,0,3,0.5); +} + +a.athanks { + background-color:rgba(0,0,0,0);; + } + +a:hover { + background-color:rgba(30,0,124,0.5); +border-color: white; +} + +a:visited { + color: #90B090; +} +label { + font-size: medium; +} + + +.thanks { + display: inline; + font-size: small; +} +.blogpost { + border-top: solid 0.5px; + border-bottom: dashed 0.5px; + padding-top: 3px; +} +.editblog { + width: 95%; + height: 95%; +} +.metablog { + font-style: italic; + font-size: small; + text-align: right; + display: inline; +} + +.blogtitle { + display:inline; +} +.contenu { +padding-left: 20px; +} + +.validation-summary-errors{ + color: #f88; +} +.pied { +} + +.actionlink { + color: #B0B080; + border: solid .5px; + right:3px; + padding: 4px; + border-radius:25px; + background-color:rgba(0,0,64,0.7); +} + +.code { + font-family: "monospace"; + background-color: rgba(0,0,256,0.1); + border-radius:25px; + white-space: pre-wrap; +} + +.layout { + border-width: 0; + } + +.avatar { + max-width: 64px; + max-height: 64px; +} + + .shoh { display:inline; } +.hiduh { + display:none; + } + .shoh:hover { + background-color: rgba(0,60,40,.3); + border: solid rgb(256,256,0); + } +.shoh:hover + .hiduh { + display:block; position:absolute; left:20px; right:20px; + background-color: rgb(0,0,40); border: solid rgb(256,256,0); + } +.comment { + border-radius:25px; + border-width:1px; + border-style: solid; + border-color:rgb(0,64,0); + } + +@media print { + body {background-color:white;color:black;} + .postcomment,#login,.actionlink{ display:none;} + } + +@media all and (max-width: 15em) { + section, aside { + float: none; + width: auto; + } +} diff --git a/web/table.tdeps.sql b/web/table.tdeps.sql new file mode 100644 index 00000000..e185d1ac --- /dev/null +++ b/web/table.tdeps.sql @@ -0,0 +1,6 @@ +CREATE TABLE TaskDeps (idtask bigint NOT NULL , +iddep bigint NOT NULL , +CONSTRAINT TaskDeps_pk_new PRIMARY KEY (idtask,iddep), +CONSTRAINT TaskDeps_fk_new FOREIGN KEY (idtask) REFERENCES public.tasks (id), +CONSTRAINT TaskDeps_fk_new FOREIGN KEY (iddep) REFERENCES public.tasks (id) +); diff --git a/web/test-results/maeweb.csproj-Debug-2013-11-28.xml b/web/test-results/maeweb.csproj-Debug-2013-11-28.xml new file mode 100644 index 00000000..cc156fde --- /dev/null +++ b/web/test-results/maeweb.csproj-Debug-2013-11-28.xml @@ -0,0 +1,112 @@ + + + + + + + + + 2013-11-28T00:57:03 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-11-28T01:02:44 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + 2013-11-28T00:57:03 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-11-28T01:02:44 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-11-28T01:04:49 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + + + \ No newline at end of file diff --git a/web/test-results/maeweb.csproj-Debug-2013-12-12.xml b/web/test-results/maeweb.csproj-Debug-2013-12-12.xml new file mode 100644 index 00000000..db708bac --- /dev/null +++ b/web/test-results/maeweb.csproj-Debug-2013-12-12.xml @@ -0,0 +1,141 @@ + + + + + 2013-12-12T00:23:40 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-12-12T01:29:23 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + 2013-12-12T00:23:40 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-12-12T01:29:23 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + 2013-12-12T00:23:40 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-12-12T01:29:23 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + 2013-12-12T00:23:40 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 2013-12-12T01:29:23 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + + + \ No newline at end of file diff --git a/web/test-results/maeweb.csproj-Debug-2013-12-16.xml b/web/test-results/maeweb.csproj-Debug-2013-12-16.xml new file mode 100644 index 00000000..dbf13644 --- /dev/null +++ b/web/test-results/maeweb.csproj-Debug-2013-12-16.xml @@ -0,0 +1,19 @@ + + + + + 2013-12-16T03:01:39 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + \ No newline at end of file diff --git a/web/test-results/maeweb.csproj.test-cache b/web/test-results/maeweb.csproj.test-cache new file mode 100644 index 0000000000000000000000000000000000000000..cb1e00be849a3fc24b364d2669c59ea48c384cb8 GIT binary patch literal 1312 zcmbVK%Wl&^6rCpa#C8&zLMgBE6pIQZX9r8D0u_i7ArjgJVlhcBipAIto-s6h0sp`+ z@GRUC^RNo%Vjiog1j~1`qJx&;|!Y`?;Fzsj)J@gm86_Eb zJkh#?WTb^?w8iqG>1=#iW*HSePVZMX)0sF~S_+ri`^wnEf}I{FDS2>Oc(_74Hy#-=)Y)f=aow&m71`p*%JYk&u+8xefSV&`=~XrdJ%(qH z3V^S2ouSTuM-+mweurNTz^eKiNCi0kvrOuTG?M2)xRBgr(!l@7r(Ewmwt!XZZ6Oul z>Rn*6n4-MMbXiDV;!XRwYV4*gFaHU>@>giMjSXPcj;3LzX6&gRn`Ci literal 0 HcmV?d00001 diff --git a/web/uninstdb.sql b/web/uninstdb.sql new file mode 100644 index 00000000..8537c0c0 --- /dev/null +++ b/web/uninstdb.sql @@ -0,0 +1,6 @@ + + DROP TABLE hr; + DROP TABLE taskdeps; + DROP TABLE tasks; + DROP TABLE projet; + diff --git a/web/uninstdbws.sql b/web/uninstdbws.sql new file mode 100644 index 00000000..29482b18 --- /dev/null +++ b/web/uninstdbws.sql @@ -0,0 +1,5 @@ + + DROP table usersroles CASCADE; + drop table roles CASCADE; + Drop table users CASCADE; + diff --git a/yavscModel/Admin/DataAccess.cs b/yavscModel/Admin/DataAccess.cs new file mode 100644 index 00000000..0106bc6e --- /dev/null +++ b/yavscModel/Admin/DataAccess.cs @@ -0,0 +1,84 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace yavscModel.Admin +{ + public class DataAccess { + private string host = "localhost"; + + [StringLength(2056)] + public string Host { + get { + return host; + } + set { + host = value; + } + } + + private int port = 5432; + + public int Port { + get { + return port; + } + set { + port = value; + } + } + + private string dbname = "yavsc"; + + public string Dbname { + get { + return dbname; + } + set { + dbname = value; + } + } + + private string dbuser = "postgres"; + + public string Dbuser { + get { + return dbuser; + } + set { + dbuser = value; + } + } + + private string dbpassword ; + private string backupPrefix= "backup/global.backup"; + + public string BackupPrefix { + get { + return backupPrefix; + } + set { + backupPrefix = value; + } + } + + [Required(ErrorMessage ="Please, specify a password")] + public string Password { + get { return dbpassword; } + set { dbpassword = value; } + } + + public string [] GetBackupDirs() + { + List res = new List (); + string bkpdir = new FileInfo (backupPrefix).DirectoryName; + DirectoryInfo bkpdiri = new DirectoryInfo(bkpdir); + foreach (DirectoryInfo di in bkpdiri.EnumerateDirectories()) + res.Add (Path.Combine(bkpdir,di.Name)); + return res.ToArray (); + } + } + +} diff --git a/yavscModel/Admin/RestoreQuery.cs b/yavscModel/Admin/RestoreQuery.cs new file mode 100644 index 00000000..022c99a6 --- /dev/null +++ b/yavscModel/Admin/RestoreQuery.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace yavscModel.Admin +{ + public class RestoreQuery: DataAccess + { + [Required] + [StringLength(2056)] + public string FileName { get; set ; } + + public RestoreQuery () + { + } + } +} + diff --git a/yavscModel/Blogs/BlogEditCommentModel.cs b/yavscModel/Blogs/BlogEditCommentModel.cs new file mode 100644 index 00000000..cd514ec3 --- /dev/null +++ b/yavscModel/Blogs/BlogEditCommentModel.cs @@ -0,0 +1,26 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using Npgsql.Web.Blog.DataModel; + +namespace yavscModel +{ + public class BlogEditCommentModel:Comment + { + [DisplayName("Prévisualiser")] + [Required] + public bool Preview { get; set; } + /* TODO Clean + public BlogEditCommentModel(Comment be) { + this.Preview = true; + this.Content = be.Content; + this.Posted = be.Posted; + this.Modified = be.Modified; + this.Visible = be.Visible; + this.From = be.From; + this.PostId = be.PostId; + this.Id = be.Id; + } */ + } +} + diff --git a/yavscModel/Blogs/BlogEditEntryModel.cs b/yavscModel/Blogs/BlogEditEntryModel.cs new file mode 100644 index 00000000..d454ca3c --- /dev/null +++ b/yavscModel/Blogs/BlogEditEntryModel.cs @@ -0,0 +1,29 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using Npgsql.Web.Blog.DataModel; + +namespace yavscModel +{ + public class BlogEditEntryModel:BlogEntry + { + [DisplayName("Prévisualiser")] + [Required] + public bool Preview { get; set; } + public BlogEditEntryModel () + { + } + + public BlogEditEntryModel(BlogEntry be) { + this.Preview = true; + this.Content = be.Content; + this.Title = be.Title; + this.Posted = be.Posted; + this.Modified = be.Modified; + this.Visible = be.Visible; + this.UserName = be.UserName; + this.Id = be.Id; + } + } +} + diff --git a/yavscModel/FileSystem/FileInfoCollection.cs b/yavscModel/FileSystem/FileInfoCollection.cs new file mode 100644 index 00000000..3a2897b6 --- /dev/null +++ b/yavscModel/FileSystem/FileInfoCollection.cs @@ -0,0 +1,12 @@ +using System; +using System.IO; +using System.Collections.Generic; + +namespace FileSystem +{ + public class FileInfoCollection: List + { + + } +} + diff --git a/yavscModel/Properties/AssemblyInfo.cs b/yavscModel/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a22ab5b7 --- /dev/null +++ b/yavscModel/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("YavscModel")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("paul")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/yavscModel/RolesAndMemebers/ChangePasswordModel.cs b/yavscModel/RolesAndMemebers/ChangePasswordModel.cs new file mode 100644 index 00000000..cf20cc38 --- /dev/null +++ b/yavscModel/RolesAndMemebers/ChangePasswordModel.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace yavscModel.RolesAndMembers +{ + public class ChangePasswordModel + { + [Required(ErrorMessage = "Please enter a Username")] + public string Username { get; set; } + + [Required(ErrorMessage = "Please your old Password")] + public string OldPassword { get; set; } + + [Required(ErrorMessage = "Please enter a new Password")] + public string NewPassword { get; set; } + + [Required(ErrorMessage = "Please confirm the new Password")] + public string ConfirmPassword { get; set; } + + } +} + diff --git a/yavscModel/RolesAndMemebers/LoginModel.cs b/yavscModel/RolesAndMemebers/LoginModel.cs new file mode 100644 index 00000000..2636a0ef --- /dev/null +++ b/yavscModel/RolesAndMemebers/LoginModel.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel; + +namespace yavscModel.RolesAndMembers +{ + public class LoginModel + { + [DisplayName("Nom d'utilisateur")] + [Required(ErrorMessage = "S'il vous plait, entrez un nom d'utilisateur ([a-z]|[A-Z]|[-_.~])+")] + [RegularExpression("([a-z]|[A-Z]|[-_.~])+")] + public string UserName { get; set; } + + [DisplayName("Mot de passe")] + [Required(ErrorMessage = "S'il vous plait, entez un mot de passe")] + [RegularExpression("([a-z]|[A-Z]|[-_.~#{}`'\\^])+")] + public string Password { get; set; } + + [Display(Name = "Se souvenir du mot de passe")] + public bool RememberMe { get; set; } + } +} diff --git a/yavscModel/RolesAndMemebers/NewAdminModel.cs b/yavscModel/RolesAndMemebers/NewAdminModel.cs new file mode 100644 index 00000000..cc1a3ed6 --- /dev/null +++ b/yavscModel/RolesAndMemebers/NewAdminModel.cs @@ -0,0 +1,13 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace yavscModel.RolesAndMembers +{ + public class NewAdminModel + { + [Required(ErrorMessage = "S'il vous plait, entrez un nom d'utilisateur")] + [Display(Name = "Nom du nouvel administrateur", Description="Nom de l'utilisateur à enregistrer comme administrateur")] + public string UserName { get; set ; } + } +} + diff --git a/yavscModel/RolesAndMemebers/NewRoleModel.cs b/yavscModel/RolesAndMemebers/NewRoleModel.cs new file mode 100644 index 00000000..5a295878 --- /dev/null +++ b/yavscModel/RolesAndMemebers/NewRoleModel.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel; + +namespace yavscModel.RolesAndMembers +{ + public class NewRoleModel + { + [Required] + [StringLength(255)] + [DisplayName("Nom du rôle")] + public string RoleName { get; set; } + } +} + diff --git a/yavscModel/RolesAndMemebers/Profile.cs b/yavscModel/RolesAndMemebers/Profile.cs new file mode 100644 index 00000000..d3bc21ae --- /dev/null +++ b/yavscModel/RolesAndMemebers/Profile.cs @@ -0,0 +1,63 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Web.Profile; + +namespace yavscModel.RolesAndMembers +{ + public class Profile + { + [DisplayName("Adresse")] + [StringLength(2047)] + public string Address { get; set; } + + [DisplayName("Ville")] + [StringLength(255)] + public string CityAndState { get; set; } + + [DisplayName("Code Postal")] + [StringLength(9)] + public string ZipCode { get; set; } + + [DisplayName("Pays")] + [StringLength(99)] + public string Country { get; set; } + + [DisplayName("Site Web")] + [StringLength(255)] + public string WebSite { get; set; } + + [DisplayName("Blog visible")] + public bool BlogVisible { get; set; } + + [DisplayName("Titre du blog")] + public string BlogTitle { get; set; } + + public void FromProfileBase(ProfileBase profile) + { + object b = profile.GetPropertyValue ("BlogVisible"); + BlogVisible = (b is DBNull) ? true : (bool)b; + + object s = profile.GetPropertyValue ("BlogTitle"); + BlogTitle = (s is DBNull) ? null : (string)s; + + s = profile.GetPropertyValue("Address"); + Address = (s is DBNull)?null:(string)s; + + s = profile.GetPropertyValue("CityAndState"); + CityAndState = (s is DBNull)?null:(string)s; + + s = profile.GetPropertyValue("Country"); + Country = (s is DBNull)?null:(string)s; + + s = profile.GetPropertyValue("ZipCode"); + ZipCode = (s is DBNull)?null:(string)s; + + + s = profile.GetPropertyValue ("WebSite"); + WebSite = (s is DBNull) ? null : (string)s; + + } + } +} + diff --git a/yavscModel/RolesAndMemebers/RegisterViewModel.cs b/yavscModel/RolesAndMemebers/RegisterViewModel.cs new file mode 100644 index 00000000..306b7848 --- /dev/null +++ b/yavscModel/RolesAndMemebers/RegisterViewModel.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace yavscModel.RolesAndMembers +{ + public class RegisterViewModel + { + [DisplayName("Nom d'utilisateur")] + [Required(ErrorMessage = "S'il vous plait, entrez un nom d'utilisateur")] + public string UserName { get; set; } + + [DisplayName("Mot de passe")] + [Required(ErrorMessage = "S'il vous plait, entez un mot de passe")] + public string Password { get; set; } + + [DisplayName("Confirmation du mot de passe")] + public string ConfirmPassword { get; set; } + + [DisplayName("Adresse e-mail")] + [Required(ErrorMessage = "S'il vous plait, entrez un e-mail valide")] + public string Email { get; set; } + } +} + diff --git a/yavscModel/WorkFlow/Estimate.cs b/yavscModel/WorkFlow/Estimate.cs new file mode 100644 index 00000000..0444ad8f --- /dev/null +++ b/yavscModel/WorkFlow/Estimate.cs @@ -0,0 +1,22 @@ +using System; + +namespace yavscModel.WorkFlow +{ + public class Estimate + { + public Estimate () + { + } + public string Description { get; set; } + public decimal Ciffer { + get { + decimal total = 0; + foreach (Writting l in Lines) + total += l.UnitaryCost * l.Count; + return total; + } + } + public Writting[] Lines { get; set; } + } +} + diff --git a/yavscModel/WorkFlow/IContent.cs b/yavscModel/WorkFlow/IContent.cs new file mode 100644 index 00000000..f608f3f9 --- /dev/null +++ b/yavscModel/WorkFlow/IContent.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace yavscModel.WorkFlow +{ + public interface IContent + { + object Data { get; set; } + string MimeType { get; set; } + + } +} + diff --git a/yavscModel/WorkFlow/IContentProvider.cs b/yavscModel/WorkFlow/IContentProvider.cs new file mode 100644 index 00000000..6d47549e --- /dev/null +++ b/yavscModel/WorkFlow/IContentProvider.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; + +namespace yavscModel.WorkFlow +{ + public interface IContentProvider: IDisposable + { + string Order (IWFCommand c); + IContent Get (string orderId); + } +} + diff --git a/yavscModel/WorkFlow/IWFCommand.cs b/yavscModel/WorkFlow/IWFCommand.cs new file mode 100644 index 00000000..7de8dcb8 --- /dev/null +++ b/yavscModel/WorkFlow/IWFCommand.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace yavscModel.WorkFlow +{ + public interface IWFCommand + { + } +} + diff --git a/yavscModel/WorkFlow/IWFModule.cs b/yavscModel/WorkFlow/IWFModule.cs new file mode 100644 index 00000000..6b65ae02 --- /dev/null +++ b/yavscModel/WorkFlow/IWFModule.cs @@ -0,0 +1,13 @@ +using System; +using yavscModel.WorkFlow; +using System.Web.Mvc; + +namespace WorkFlow +{ + public interface IWFModule + { + int GetState (IWFCommand c); + int Handle (IWFCommand c,FormCollection collection); + } +} + diff --git a/yavscModel/WorkFlow/NewProjectModel.cs b/yavscModel/WorkFlow/NewProjectModel.cs new file mode 100644 index 00000000..5daf7771 --- /dev/null +++ b/yavscModel/WorkFlow/NewProjectModel.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel; + +namespace yavscModel.WorkFlow +{ + public class NewProjectModel + { + [DisplayName("Nom du projet")] + [Required()] + public string Name { get; set; } + + [DisplayName("Manager du projet")] + [Required] + public string Manager { get; set; } + + [DisplayName("Description du projet")] + [Required] + public string Description { get; set; } + + } +} + diff --git a/yavscModel/WorkFlow/WFOrder.cs b/yavscModel/WorkFlow/WFOrder.cs new file mode 100644 index 00000000..77378a18 --- /dev/null +++ b/yavscModel/WorkFlow/WFOrder.cs @@ -0,0 +1,39 @@ +using System; +using SalesCatalog.Model; +using yavscModel.WorkFlow; + +namespace WorkFlow +{ + public class WFOrder : IWFCommand + { + private Product p; + private DateTime date; + private string catref; + public WFOrder(Product prod,string catalogReference){ + date = DateTime.Now; + catref=catalogReference; + p = prod; + } + public override string ToString () + { + return string.Format ("[Commande date={0} prodref={1}, cat={2}]",date,p.Reference,catref); + } + + #region IWFCommand implementation + + public string CatalogReference { + get { + return catref; + } + } + + public DateTime OrderDate { + get { + return date; + } + } + + #endregion + } +} + diff --git a/yavscModel/WorkFlow/Writting.cs b/yavscModel/WorkFlow/Writting.cs new file mode 100644 index 00000000..c5710edd --- /dev/null +++ b/yavscModel/WorkFlow/Writting.cs @@ -0,0 +1,13 @@ +using System; + +namespace yavscModel.WorkFlow +{ + public class Writting + { + public decimal UnitaryCost { get; set; } + public int Count { get; set; } + public string ProductReference { get; set; } + public string Description { get; set; } + } +} + diff --git a/yavscModel/yavscModel.csproj b/yavscModel/yavscModel.csproj new file mode 100644 index 00000000..6737e2f5 --- /dev/null +++ b/yavscModel/yavscModel.csproj @@ -0,0 +1,89 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {68F5B80A-616E-4C3C-91A0-828AA40000BD} + Library + yavscModel + yavscModel + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {C6E9E91B-97D3-48D9-8AA7-05356929E162} + NpgsqlBlogProvider + + + {90BF2234-7252-4CD5-B2A4-17501B19279B} + SalesCatalog + + + + + + + + + + + + \ No newline at end of file diff --git a/yavscclient/MyClass.cs b/yavscclient/MyClass.cs new file mode 100644 index 00000000..6e2594aa --- /dev/null +++ b/yavscclient/MyClass.cs @@ -0,0 +1,78 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using SalesCatalog.Model; +using System.Net.Http.Headers; +using System.Collections.Generic; +using System.Net.Http.Formatting; +using Newtonsoft.Json; + +namespace Yavsc +{ + public class MainClass + { + public static string ServiceUrl{ get; set; } + + public static void Main(string [] args) + { + foreach (string s in args) { + if (Uri.IsWellFormedUriString (s,UriKind.Absolute)) { + // TODO create a client + } + GetCatalog (); + } + } + static HttpClient GetClient() + { + HttpClient client = new HttpClient (); + + client.BaseAddress = new Uri (ServiceUrl); + + // Add an Accept header for JSON format. + client.DefaultRequestHeaders.Accept.Add ( + new MediaTypeWithQualityHeaderValue ("application/json")); + return client; + } + + static void GetCatalog() { + HttpClient client = GetClient (); + + HttpResponseMessage response = client.GetAsync("api/FrontOffice/Catalog").Result; // Blocking call! + if (response.IsSuccessStatusCode) + { + + var jsonFormatter = new JsonMediaTypeFormatter(); + jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto; + jsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + // Parse the response body. Blocking! + Catalog cat = response.Content.ReadAsAsync(new List{jsonFormatter},null).Result; + foreach (var p in cat.Brands) + { + Console.WriteLine("{0}\t{1};\t{2}", p.Name, p.Categories.Length, p.Slogan); + } + } + else + { + Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); + } + } + + public void UpLoad(string fileName) + { + using (var client = GetClient()) + { + using (var content = new MultipartFormDataContent()) + { + var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName));//(); + fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") + { + FileName = fileName + }; + content.Add(fileContent); + var result = client.PostAsync(ServiceUrl, content).Result; + } + } + } + } +} + diff --git a/yavscclient/Properties/AssemblyInfo.cs b/yavscclient/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..8ac65528 --- /dev/null +++ b/yavscclient/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("YavscClient")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("Paul Schneider")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/yavscclient/YavscClient.csproj b/yavscclient/YavscClient.csproj new file mode 100644 index 00000000..ace26675 --- /dev/null +++ b/yavscclient/YavscClient.csproj @@ -0,0 +1,55 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {EEFCECE6-3B7F-4BBE-B7AF-69377AF3CF39} + Exe + maeclient + yavscclient + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + true + + + full + true + bin\Release + prompt + 4 + false + true + + + + + + + ..\..\..\..\..\usr\lib\mono\4.5\System.Net.Http.Formatting.dll + False + + + + + + + + + + + {90BF2234-7252-4CD5-B2A4-17501B19279B} + SalesCatalog + + + \ No newline at end of file