2010-04-28 18:21:32 -07:00
using System ;
using System.Linq ;
using System.Web ;
using Orchard.ContentManagement ;
2010-06-04 13:37:34 -07:00
using Orchard.ContentManagement.MetaData ;
2010-04-28 18:21:32 -07:00
using Orchard.Core.Common.Models ;
2010-06-29 15:07:40 -07:00
using Orchard.Core.Common.Settings ;
2010-07-22 23:01:57 -07:00
using Orchard.Core.Contents.Extensions ;
2010-09-10 13:03:29 -07:00
using Orchard.Core.Navigation.Models ;
2010-07-13 02:52:02 -07:00
using Orchard.Core.Routable.Models ;
2010-07-19 13:27:16 -07:00
using Orchard.Core.Settings.Descriptor.Records ;
2010-04-28 18:21:32 -07:00
using Orchard.Core.Settings.Models ;
using Orchard.Data ;
2010-06-29 16:17:08 -07:00
using Orchard.Data.Migration.Interpreters ;
using Orchard.Data.Migration.Schema ;
2010-04-28 18:21:32 -07:00
using Orchard.Environment ;
using Orchard.Environment.Configuration ;
2010-10-15 15:18:53 -07:00
using Orchard.Environment.Extensions ;
2010-04-28 18:21:32 -07:00
using Orchard.Environment.ShellBuilders ;
2010-06-11 17:28:46 -07:00
using Orchard.Environment.Descriptor ;
using Orchard.Environment.Descriptor.Models ;
2010-09-16 13:22:18 -07:00
using Orchard.Indexing ;
2010-04-28 18:21:32 -07:00
using Orchard.Localization ;
2010-06-01 17:09:26 -07:00
using Orchard.Localization.Services ;
2010-07-09 17:56:58 -07:00
using Orchard.Reports.Services ;
2010-04-28 18:21:32 -07:00
using Orchard.Security ;
using Orchard.Settings ;
using Orchard.Themes ;
2010-06-25 17:06:02 -07:00
using Orchard.Environment.State ;
2010-06-29 16:17:08 -07:00
using Orchard.Data.Migration ;
2010-11-04 20:37:35 -07:00
using Orchard.Themes.Services ;
2010-10-12 00:57:52 -07:00
using Orchard.Widgets.Models ;
2010-10-15 15:18:53 -07:00
using Orchard.Widgets ;
2010-04-28 18:21:32 -07:00
namespace Orchard.Setup.Services {
public class SetupService : ISetupService {
private readonly ShellSettings _shellSettings ;
private readonly IOrchardHost _orchardHost ;
private readonly IShellSettingsManager _shellSettingsManager ;
private readonly IShellContainerFactory _shellContainerFactory ;
private readonly ICompositionStrategy _compositionStrategy ;
2010-06-25 17:06:02 -07:00
private readonly IProcessingEngine _processingEngine ;
2010-04-28 18:21:32 -07:00
public SetupService (
ShellSettings shellSettings ,
IOrchardHost orchardHost ,
IShellSettingsManager shellSettingsManager ,
IShellContainerFactory shellContainerFactory ,
2010-06-25 17:06:02 -07:00
ICompositionStrategy compositionStrategy ,
2010-06-29 11:28:21 -07:00
IProcessingEngine processingEngine ) {
2010-04-28 18:21:32 -07:00
_shellSettings = shellSettings ;
_orchardHost = orchardHost ;
_shellSettingsManager = shellSettingsManager ;
_shellContainerFactory = shellContainerFactory ;
_compositionStrategy = compositionStrategy ;
2010-06-25 17:06:02 -07:00
_processingEngine = processingEngine ;
2010-04-28 18:21:32 -07:00
T = NullLocalizer . Instance ;
}
2010-06-02 13:54:50 -07:00
public Localizer T { get ; set ; }
2010-04-28 18:21:32 -07:00
2010-05-10 16:01:04 -07:00
public ShellSettings Prime ( ) {
return _shellSettings ;
}
2010-04-28 18:21:32 -07:00
public void Setup ( SetupContext context ) {
2010-05-13 19:07:53 -07:00
// The vanilla Orchard distibution has the following features enabled.
if ( context . EnabledFeatures = = null | | context . EnabledFeatures . Count ( ) = = 0 ) {
string [ ] hardcoded = {
"Orchard.Framework" ,
"Common" ,
2010-09-07 16:00:04 -07:00
"Shapes" ,
2010-06-07 16:02:54 -07:00
"Contents" ,
2010-05-13 19:07:53 -07:00
"Dashboard" ,
2010-09-10 16:50:43 -07:00
"Reports" ,
2010-09-17 01:00:24 -07:00
"Feeds" ,
2010-05-13 19:07:53 -07:00
"HomePage" ,
2010-09-10 13:03:29 -07:00
"Navigation" ,
2010-09-17 01:00:24 -07:00
"Scheduling" ,
2010-09-15 14:06:34 -07:00
"Indexing" ,
2010-09-22 11:36:39 -07:00
"Localization" ,
2010-07-13 02:52:02 -07:00
"Routable" ,
2010-05-13 19:07:53 -07:00
"Settings" ,
2010-08-30 15:06:52 -07:00
"Messaging" ,
2010-05-13 19:07:53 -07:00
"Orchard.Users" ,
"Orchard.Roles" ,
2010-09-14 14:21:35 -07:00
"TinyMce" ,
2010-09-10 13:14:07 -07:00
"PackagingServices" ,
2010-11-14 14:34:01 -08:00
"Orchard.Pages" ,
2010-09-10 13:14:07 -07:00
"Orchard.Modules" ,
2010-05-13 19:07:53 -07:00
"Orchard.Themes" ,
2010-10-25 19:53:16 -07:00
"Orchard.PublishLater" ,
2010-09-17 01:00:24 -07:00
"Orchard.Blogs" ,
2010-09-15 12:13:19 -07:00
"Orchard.Comments" ,
2010-09-14 14:49:34 -07:00
"Orchard.Tags" ,
2010-09-14 15:39:11 -07:00
"Orchard.Media" ,
2010-09-29 13:35:57 -07:00
"Orchard.Widgets" ,
2010-10-28 15:30:14 -07:00
"Orchard.jQuery" ,
2010-11-08 12:12:52 -08:00
"TheThemeMachine" ,
2010-08-31 11:50:07 -07:00
} ;
2010-05-13 19:07:53 -07:00
context . EnabledFeatures = hardcoded ;
}
2010-07-08 15:18:13 -07:00
2010-05-10 16:01:04 -07:00
var shellSettings = new ShellSettings ( _shellSettings ) ;
2010-06-04 13:37:34 -07:00
2010-05-10 16:01:04 -07:00
if ( string . IsNullOrEmpty ( shellSettings . DataProvider ) ) {
shellSettings . DataProvider = context . DatabaseProvider ;
shellSettings . DataConnectionString = context . DatabaseConnectionString ;
shellSettings . DataTablePrefix = context . DatabaseTablePrefix ;
2010-05-13 19:07:53 -07:00
}
2010-04-28 18:21:32 -07:00
var shellDescriptor = new ShellDescriptor {
2010-05-28 13:03:57 -07:00
Features = context . EnabledFeatures . Select ( name = > new ShellFeature { Name = name } )
2010-04-28 18:21:32 -07:00
} ;
2010-07-19 17:46:35 -07:00
var shellBlueprint = _compositionStrategy . Compose ( shellSettings , shellDescriptor ) ;
2010-04-28 18:21:32 -07:00
// initialize database explicitly, and store shell descriptor
2010-07-19 17:46:35 -07:00
var bootstrapLifetimeScope = _shellContainerFactory . CreateContainer ( shellSettings , shellBlueprint ) ;
2010-09-02 16:34:17 -07:00
using ( var environment = bootstrapLifetimeScope . CreateWorkContextScope ( ) ) {
2010-07-19 13:27:16 -07:00
// check if the database is already created (in case an exception occured in the second phase)
var shellDescriptorRepository = environment . Resolve < IRepository < ShellDescriptorRecord > > ( ) ;
try {
shellDescriptorRepository . Get ( x = > true ) ;
}
catch {
var schemaBuilder = new SchemaBuilder ( environment . Resolve < IDataMigrationInterpreter > ( ) ) ;
var reportsCoordinator = environment . Resolve < IReportsCoordinator > ( ) ;
reportsCoordinator . Register ( "Data Migration" , "Setup" , "Orchard installation" ) ;
schemaBuilder . CreateTable ( "Orchard_Framework_DataMigrationRecord" ,
table = > table
. Column < int > ( "Id" , column = > column . PrimaryKey ( ) . Identity ( ) )
. Column < string > ( "DataMigrationClass" )
. Column < int > ( "Version" ) ) ;
var dataMigrationManager = environment . Resolve < IDataMigrationManager > ( ) ;
2010-07-21 17:19:28 -07:00
dataMigrationManager . Update ( "Settings" ) ;
2010-07-19 13:27:16 -07:00
foreach ( var feature in context . EnabledFeatures ) {
dataMigrationManager . Update ( feature ) ;
}
environment . Resolve < IShellDescriptorManager > ( ) . UpdateShellDescriptor (
0 ,
shellDescriptor . Features ,
shellDescriptor . Parameters ) ;
}
2010-04-28 18:21:32 -07:00
}
2010-06-25 17:06:02 -07:00
// in effect "pump messages" see PostMessage circa 1980
while ( _processingEngine . AreTasksPending ( ) )
_processingEngine . ExecuteNextTask ( ) ;
2010-04-28 18:21:32 -07:00
// creating a standalone environment.
// in theory this environment can be used to resolve any normal components by interface, and those
// components will exist entirely in isolation - no crossover between the safemode container currently in effect
// must mark state as Running - otherwise standalone enviro is created "for setup"
shellSettings . State = new TenantState ( "Running" ) ;
using ( var environment = _orchardHost . CreateStandaloneEnvironment ( shellSettings ) ) {
try {
2010-10-15 15:18:53 -07:00
CreateTenantData ( context , environment ) ;
2010-04-28 18:21:32 -07:00
}
catch {
environment . Resolve < ITransactionManager > ( ) . Cancel ( ) ;
throw ;
}
}
_shellSettingsManager . SaveSettings ( shellSettings ) ;
}
2010-10-15 15:18:53 -07:00
private void CreateTenantData ( SetupContext context , IWorkContextScope environment ) {
// create superuser
var membershipService = environment . Resolve < IMembershipService > ( ) ;
var user =
membershipService . CreateUser ( new CreateUserParams ( context . AdminUsername , context . AdminPassword ,
String . Empty , String . Empty , String . Empty ,
true ) ) ;
// set superuser as current user for request (it will be set as the owner of all content items)
var authenticationService = environment . Resolve < IAuthenticationService > ( ) ;
authenticationService . SetAuthenticatedUserForRequest ( user ) ;
// set site name and settings
var siteService = environment . Resolve < ISiteService > ( ) ;
var siteSettings = siteService . GetSiteSettings ( ) . As < SiteSettingsPart > ( ) ;
siteSettings . Record . SiteSalt = Guid . NewGuid ( ) . ToString ( "N" ) ;
siteSettings . Record . SiteName = context . SiteName ;
siteSettings . Record . SuperUser = context . AdminUsername ;
siteSettings . Record . PageTitleSeparator = " - " ;
siteSettings . Record . SiteCulture = "en-US" ;
// set site theme
2010-11-04 20:37:35 -07:00
var themeService = environment . Resolve < ISiteThemeService > ( ) ;
2010-10-15 15:18:53 -07:00
themeService . SetSiteTheme ( "TheThemeMachine" ) ;
// add default culture
var cultureManager = environment . Resolve < ICultureManager > ( ) ;
cultureManager . AddCulture ( "en-US" ) ;
var contentManager = environment . Resolve < IContentManager > ( ) ;
// this needs to exit the standalone environment? rework this process entirely?
// simulate installation-time module activation events
//var hackInstallationGenerator = environment.Resolve<IHackInstallationGenerator>();
//hackInstallationGenerator.GenerateInstallEvents();
var contentDefinitionManager = environment . Resolve < IContentDefinitionManager > ( ) ;
2010-11-14 14:34:01 -08:00
//todo: (heskew) pull these definitions (and initial content creation) out into a distribution configuration when we have that capability
2010-10-15 15:18:53 -07:00
contentDefinitionManager . AlterTypeDefinition ( "BlogPost" , cfg = > cfg
. WithPart ( "CommentsPart" )
. WithPart ( "TagsPart" )
. WithPart ( "LocalizationPart" )
2010-11-04 15:25:16 -07:00
. Draftable ( )
2010-10-15 15:18:53 -07:00
. Indexed ( )
) ;
contentDefinitionManager . AlterTypeDefinition ( "Page" , cfg = > cfg
. WithPart ( "TagsPart" )
. WithPart ( "LocalizationPart" )
2010-11-04 15:25:16 -07:00
. Draftable ( )
2010-10-15 15:18:53 -07:00
. Indexed ( )
) ;
contentDefinitionManager . AlterPartDefinition ( "BodyPart" , cfg = > cfg
. WithSetting ( "BodyPartSettings.FlavorDefault" , BodyPartSettings . FlavorDefaultDefault ) ) ;
// If "Orchard.Widgets" is enabled, setup default layers and widgets
var extensionManager = environment . Resolve < IExtensionManager > ( ) ;
var shellDescriptor = environment . Resolve < ShellDescriptor > ( ) ;
if ( extensionManager . EnabledFeatures ( shellDescriptor ) . Where ( d = > d . Name = = "Orchard.Widgets" ) . Any ( ) ) {
// Create default layers
var layerInitializer = environment . Resolve < IDefaultLayersInitializer > ( ) ;
layerInitializer . CreateDefaultLayers ( ) ;
// add a layer for the homepage
var homepageLayer = contentManager . Create ( "Layer" ) ;
homepageLayer . As < LayerPart > ( ) . Name = "TheHomepage" ;
homepageLayer . As < LayerPart > ( ) . LayerRule = "url \"~/\"" ;
contentManager . Publish ( homepageLayer ) ;
// and three more for the tripel...really need this elsewhere...
var tripelFirst = contentManager . Create ( "HtmlWidget" ) ;
tripelFirst . As < WidgetPart > ( ) . LayerPart = homepageLayer . As < LayerPart > ( ) ;
tripelFirst . As < WidgetPart > ( ) . Title = T ( "First Leader Aside" ) . Text ;
tripelFirst . As < WidgetPart > ( ) . Zone = "TripelFirst" ;
tripelFirst . As < WidgetPart > ( ) . Position = "5" ;
tripelFirst . As < BodyPart > ( ) . Text = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>" ;
contentManager . Publish ( tripelFirst ) ;
var tripelSecond = contentManager . Create ( "HtmlWidget" ) ;
tripelSecond . As < WidgetPart > ( ) . LayerPart = homepageLayer . As < LayerPart > ( ) ;
tripelSecond . As < WidgetPart > ( ) . Title = T ( "Second Leader Aside" ) . Text ;
tripelSecond . As < WidgetPart > ( ) . Zone = "TripelSecond" ;
tripelSecond . As < WidgetPart > ( ) . Position = "5" ;
tripelSecond . As < BodyPart > ( ) . Text = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>" ;
contentManager . Publish ( tripelSecond ) ;
var tripelThird = contentManager . Create ( "HtmlWidget" ) ;
tripelThird . As < WidgetPart > ( ) . LayerPart = homepageLayer . As < LayerPart > ( ) ;
tripelThird . As < WidgetPart > ( ) . Title = T ( "Third Leader Aside" ) . Text ;
tripelThird . As < WidgetPart > ( ) . Zone = "TripelThird" ;
tripelThird . As < WidgetPart > ( ) . Position = "5" ;
tripelThird . As < BodyPart > ( ) . Text = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>" ;
contentManager . Publish ( tripelThird ) ;
}
// create a welcome page that's promoted to the home page
var page = contentManager . Create ( "Page" ) ;
page . As < RoutePart > ( ) . Title = T ( "Welcome to Orchard!" ) . Text ;
2010-10-19 20:55:13 -07:00
page . As < BodyPart > ( ) . Text = "<p>You’ ve successfully setup your Orchard Site and this is the homepage of your new site. Here are a few things you can look at to get familiar with the application. Once you feel confident you don’ t need this anymore, you can <a href=\"/Admin/Contents/Edit/7\">remove this by going into editing mode</a> and replacing it with whatever you want.</p><p>First things first - You’ ll probably want to <a href=\"Admin/Settings\">manage your settings</a> and configure Orchard to your liking. After that, you can head over to <a href=\"Admin/Themes\">manage themes to change or install new themes</a> and really make it your own. Once you’ re happy with a look and feel, it’ s time for some content. You can start creating new custom content types or start with some built-in ones by <a href=\"Admin/Pages/Create\">adding a page</a>, <a href=\"Admin/Blogs/Create\">creating a blog</a> or <a href=\"Admin/Navigation\">managing your menus.</a></p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. If you’ re looking to add additional functionality, you can do so by creating your own module or installing a new one that someone has made. Modules are created by other users of Orchard just like you so if you feel up to it, <a href=\"http://www.orchardproject.net/\">please consider participating</a>. XOXO – The Orchard Team </p>" ;
2010-10-15 15:18:53 -07:00
contentManager . Publish ( page ) ;
siteSettings . Record . HomePage = "RoutableHomePageProvider;" + page . Id ;
// add a menu item for the shiny new home page
var menuItem = contentManager . Create ( "MenuItem" ) ;
menuItem . As < MenuPart > ( ) . MenuPosition = "1" ;
menuItem . As < MenuPart > ( ) . MenuText = T ( "Home" ) . ToString ( ) ;
menuItem . As < MenuPart > ( ) . OnMainMenu = true ;
menuItem . As < MenuItemPart > ( ) . Url = "" ;
//null check: temporary fix for running setup in command line
if ( HttpContext . Current ! = null ) {
authenticationService . SignIn ( user , true ) ;
}
}
2010-04-28 18:21:32 -07:00
}
}