mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Commands;
|
||||
using Orchard.DevTools.ViewModels;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Themes;
|
||||
using Orchard.UI.Admin;
|
||||
|
||||
namespace Orchard.DevTools.Controllers {
|
||||
[Themed, Admin, OrchardFeature("Orchard.DevTools.WebCommandLine")]
|
||||
public class CommandsController : Controller {
|
||||
private readonly ICommandManager _commandManager;
|
||||
|
||||
public CommandsController(ICommandManager commandManager) {
|
||||
_commandManager = commandManager;
|
||||
}
|
||||
|
||||
public ActionResult Index() {
|
||||
return Execute();
|
||||
}
|
||||
|
||||
public ActionResult Execute() {
|
||||
return View("Execute", new CommandsExecuteViewModel());
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Execute(CommandsExecuteViewModel model) {
|
||||
|
||||
var writer = new StringWriter();
|
||||
var parameters = new CommandParameters {
|
||||
Arguments = model.CommandLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries),
|
||||
Output = writer
|
||||
};
|
||||
|
||||
_commandManager.Execute(parameters);
|
||||
model.History = (model.History ?? Enumerable.Empty<string>())
|
||||
.Concat(new[] { model.CommandLine })
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
model.Results = writer.ToString();
|
||||
return View("Execute", model);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -16,4 +16,7 @@ features:
|
||||
Profiling:
|
||||
Description: Tools to help profile Orchard.
|
||||
Category: Developer
|
||||
Dependencies: Orchard.DevTools
|
||||
Dependencies: Orchard.DevTools
|
||||
Orchard.DevTools.WebCommandLine:
|
||||
Description: Enables site administrators to execute Orchard.exe commands via web interface
|
||||
Category: Developer
|
||||
|
@@ -72,6 +72,7 @@
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Commands\ProfilingCommands.cs" />
|
||||
<Compile Include="Commands\ScaffoldingCommands.cs" />
|
||||
<Compile Include="Controllers\CommandsController.cs" />
|
||||
<Compile Include="Controllers\ContentController.cs" />
|
||||
<Compile Include="Controllers\DataMigrationController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
@@ -84,6 +85,7 @@
|
||||
<Content Include="ScaffoldingTemplates\DataMigration.txt" />
|
||||
<Compile Include="Services\ScaffoldingCommandInterpreter.cs" />
|
||||
<Compile Include="Settings\DevToolsSettings.cs" />
|
||||
<Compile Include="ViewModels\CommandsExecuteViewModel.cs" />
|
||||
<Compile Include="ViewModels\ContentIndexViewModel.cs" />
|
||||
<Compile Include="ViewModels\ContentDetailsViewModel.cs" />
|
||||
<Compile Include="ViewModels\MetadataIndexViewModel.cs" />
|
||||
@@ -95,6 +97,7 @@
|
||||
<Content Include="ScaffoldingTemplates\ModuleCsProj.txt" />
|
||||
<Content Include="ScaffoldingTemplates\ModuleManifest.txt" />
|
||||
<Content Include="ScaffoldingTemplates\ModuleWebConfig.txt" />
|
||||
<Content Include="Views\Commands\Execute.ascx" />
|
||||
<Content Include="Views\DataMigration\Index.aspx" />
|
||||
<Content Include="Views\DefinitionTemplates\DevToolsSettings.ascx" />
|
||||
<Content Include="Views\Home\_RenderableAction.ascx" />
|
||||
|
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Orchard.DevTools.ViewModels {
|
||||
public class CommandsExecuteViewModel {
|
||||
public string[] History { get; set; }
|
||||
public string CommandLine { get; set; }
|
||||
public string Results { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.DevTools.ViewModels.CommandsExecuteViewModel>" %>
|
||||
<h1>
|
||||
<%: Html.TitleForPage(T("Command line").ToString()) %></h1>
|
||||
<div>
|
||||
<% using (Html.BeginFormAntiForgeryPost(Url.Action("Execute"))) {%>
|
||||
<%:Html.ValidationSummary()%>
|
||||
<ul>
|
||||
<%for (int index = 0; index != (Model.History ?? new string[0]).Length; ++index) {%><li>
|
||||
<%:Model.History[index]%>
|
||||
<%:Html.HiddenFor(m => m.History[index])%>
|
||||
</li>
|
||||
<%
|
||||
}%></ul>
|
||||
<%:Html.LabelFor(m => m.CommandLine)%>
|
||||
<%:Html.TextBoxFor(m => m.CommandLine, new { style = "width:100%;" })%>
|
||||
<%:Html.ValidationMessageFor(m => m.CommandLine)%>
|
||||
<pre><%: Model.Results%></pre>
|
||||
<%}%>
|
||||
</div>
|
@@ -1,21 +0,0 @@
|
||||
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Navigation;
|
||||
|
||||
namespace Orchard.MetaData {
|
||||
public class AdminMenu : INavigationProvider {
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public string MenuName { get { return "admin"; } }
|
||||
|
||||
public void GetNavigation(NavigationBuilder builder)
|
||||
{
|
||||
builder.Add(T("Site Configuration"), "11",
|
||||
menu => menu
|
||||
.Add(T("Content Types (metadata)"), "3.1", item => item.Action("ContentTypeList", "Admin", new { area = "Orchard.MetaData" }).Permission(Permissions.ManageMetaData))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.Localization;
|
||||
using Orchard.MetaData.ViewModels;
|
||||
|
||||
namespace Orchard.MetaData.Controllers {
|
||||
|
||||
public class AdminController : Controller {
|
||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||
public IOrchardServices Services { get; set; }
|
||||
|
||||
public AdminController(IOrchardServices services, IContentDefinitionManager contentDefinitionManager) {
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
Services = services;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
//
|
||||
// GET: /ContentTypeList/
|
||||
|
||||
public ActionResult ContentTypeList(string id) {
|
||||
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMetaData, T("Not allowed to manage MetaData")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var contentTypes = _contentDefinitionManager.ListTypeDefinitions();
|
||||
var contentParts = _contentDefinitionManager.ListPartDefinitions();
|
||||
|
||||
var model = new ContentTypesIndexViewModel();
|
||||
|
||||
foreach (var contentType in contentTypes) {
|
||||
var contentTypeEntry = new ContentTypeEntry { Name = contentType.Name, DisplayName = contentType.Name };
|
||||
|
||||
if (contentType.Name == id) {
|
||||
foreach (var contentTypePartNameRecord in contentParts) {
|
||||
var contentTypePartEntry = new ContentTypePartEntry { Name = contentTypePartNameRecord.Name };
|
||||
foreach (var contentTypePartEntryTest in contentType.Parts) {
|
||||
if (contentTypePartEntryTest.PartDefinition.Name == contentTypePartEntry.Name) {
|
||||
contentTypePartEntry.Selected = true;
|
||||
}
|
||||
}
|
||||
model.ContentTypeParts.Add(contentTypePartEntry);
|
||||
}
|
||||
model.SelectedContentType = contentTypeEntry;
|
||||
}
|
||||
model.ContentTypes.Add(contentTypeEntry);
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// POST: /ContentTypeList/Save
|
||||
[HttpPost]
|
||||
public ActionResult Save(string id, FormCollection collection) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMetaData, T("Not allowed to manage MetaData")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var existingDefinition = _contentDefinitionManager.GetTypeDefinition(id);
|
||||
|
||||
_contentDefinitionManager.AlterTypeDefinition(id, alter => {
|
||||
foreach(var part in existingDefinition.Parts) {
|
||||
alter.RemovePart(part.PartDefinition.Name);
|
||||
}
|
||||
foreach (var formKey in collection.AllKeys) {
|
||||
if (formKey.Contains("part_")) {
|
||||
var partName = formKey.Replace("part_", "");
|
||||
alter.WithPart(partName);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return RedirectToAction("ContentTypeList", new { id });
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
name: MetaData
|
||||
antiforgery: enabled
|
||||
description: The MetaData module enables the management of the content type meta data, which describes how content types are built from parts and parts from fields.
|
||||
features:
|
||||
Orchard.MetaData:
|
||||
Description: Module for managing Orchard MetaData
|
||||
Dependencies: Common, XmlRpc
|
||||
Category: MetaData
|
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{23E04990-2A8D-41B8-9908-6DDB71EA3B23}</ProjectGuid>
|
||||
<ProjectTypeGuids>{F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.MetaData</RootNamespace>
|
||||
<AssemblyName>Orchard.MetaData</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<MvcBuildViews>false</MvcBuildViews>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
<Reference Include="System.Web.Mobile" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ViewModels\ContentTypesViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Module.txt" />
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="Views\Admin\ContentTypeList.ascx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||
<Name>Orchard.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Core\Orchard.Core.csproj">
|
||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||
<Name>Orchard.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Styles\ContentTypes.css" />
|
||||
<Content Include="Views\Web.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target> -->
|
||||
<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)" />
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>33002</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>
|
||||
</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
@@ -1,33 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Security.Permissions;
|
||||
|
||||
namespace Orchard.MetaData {
|
||||
public class Permissions : IPermissionProvider {
|
||||
public static readonly Permission ManageMetaData = new Permission { Description = "Manage MetaData", Name = "ManageMetaData" };//q: Should edit_MetaData be ManageMetaData?
|
||||
|
||||
|
||||
public string ModuleName {
|
||||
get {
|
||||
return "MetaData";
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetPermissions() {
|
||||
return new Permission[] {
|
||||
ManageMetaData,
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
|
||||
return new[] {
|
||||
new PermissionStereotype {
|
||||
Name = "Administrator",
|
||||
Permissions = new[] {ManageMetaData}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,34 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 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("Orchard.MetaData")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Orchard")]
|
||||
[assembly: AssemblyCopyright("Copyright © CodePlex Foundation 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("9b958fbe-1d0d-4975-9a1b-7e3ff5bed510")]
|
||||
|
||||
// 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.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@@ -1,35 +0,0 @@
|
||||
|
||||
.ContentTypeList
|
||||
{
|
||||
width: 100px;
|
||||
float:left;
|
||||
}
|
||||
.ContentTypePartList
|
||||
{
|
||||
width: 200px;
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.ContentTypePartListRow
|
||||
{
|
||||
height:5px;
|
||||
padding:0px;
|
||||
}
|
||||
.ContentTypePartListRowItem
|
||||
{
|
||||
background:#EAEAEA;
|
||||
|
||||
padding:0px;
|
||||
vertical-align:top;
|
||||
margin:1px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.SelectedContentPart {
|
||||
background:#D1F2A5;
|
||||
border-color:#BCD994;
|
||||
}
|
||||
.UnSelectedContentPart {
|
||||
background:#EAEAEA;
|
||||
border-color:#CCC;
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
|
||||
namespace Orchard.MetaData.ViewModels
|
||||
{
|
||||
public class ContentTypesIndexViewModel : BaseViewModel {
|
||||
public IList<ContentTypeEntry> ContentTypes { get; set; }
|
||||
public IList<ContentTypePartEntry> ContentTypeParts { get; set; }
|
||||
public ContentTypesIndexViewModel() {
|
||||
ContentTypes=new List<ContentTypeEntry>();
|
||||
ContentTypeParts = new List<ContentTypePartEntry>();
|
||||
}
|
||||
public ContentTypeEntry SelectedContentType { get; set; }
|
||||
}
|
||||
|
||||
public class ContentTypeEntry {
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public IList<ContentTypePartEntry> ContentTypeParts { get; set; }
|
||||
public ContentTypeEntry(){
|
||||
ContentTypeParts = new List<ContentTypePartEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
public class ContentTypePartEntry {
|
||||
public string Name { get; set; }
|
||||
public bool Selected { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentTypesIndexViewModel>" %>
|
||||
<%@ Import Namespace="Orchard.MetaData.ViewModels"%>
|
||||
<% Html.RegisterStyle("ContentTypes.css"); %>
|
||||
|
||||
<div class="ContentTypeList">
|
||||
<table>
|
||||
<tr>
|
||||
|
||||
<th>
|
||||
Content Types
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<% foreach (var item in Model.ContentTypes) { %>
|
||||
|
||||
<%
|
||||
var contentTypeClass = "";
|
||||
if (Model.SelectedContentType!=null && Model.SelectedContentType.Name == item.Name)
|
||||
{
|
||||
contentTypeClass = "SelectedContentPart";
|
||||
}else{
|
||||
contentTypeClass = "UnSelectedContentPart";
|
||||
}
|
||||
%>
|
||||
<tr class="<%=contentTypeClass %>">
|
||||
<td>
|
||||
<%: Html.ActionLink(string.IsNullOrWhiteSpace(item.Name) ? "unkwn" : item.Name, "ContentTypeList", new {id=item.Name})%>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<% } %>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<%if (Model.SelectedContentType!=null) {%>
|
||||
|
||||
<div class="ContentTypePartList">
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
|
||||
</th>
|
||||
<th>
|
||||
Included Content Part
|
||||
</th>
|
||||
</tr>
|
||||
<%
|
||||
using (Html.BeginFormAntiForgeryPost(Url.Action("Save",new {id=Model.SelectedContentType.Name}))) { %>
|
||||
|
||||
<% foreach (var item in Model.ContentTypeParts) { %>
|
||||
|
||||
<tr class="ContentTypePartListRow">
|
||||
<td class="ContentTypePartListRowItem">
|
||||
<%if (item.Selected)
|
||||
{%>
|
||||
<input name="<%="part_" + item.Name%>" type="checkbox" checked="checked" /><%}
|
||||
else {%>
|
||||
<input name="<%="part_" + item.Name%>" type="checkbox" /><%}%>
|
||||
</td>
|
||||
<td class="ContentTypePartListRowItem">
|
||||
<%: item.Name%>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<% } %>
|
||||
|
||||
</table>
|
||||
<p>
|
||||
<input type="submit" value="<%: T("Save") %>" />
|
||||
</p>
|
||||
<% } %>
|
||||
</div>
|
||||
<%} %>
|
||||
|
||||
|
||||
|
||||
|
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<add path="*" verb="*"
|
||||
type="System.Web.HttpNotFoundHandler"/>
|
||||
</httpHandlers>
|
||||
|
||||
<!--
|
||||
Enabling request validation in view pages would cause validation to occur
|
||||
after the input has already been processed by the controller. By default
|
||||
MVC performs request validation before a controller processes the input.
|
||||
To change this behavior apply the ValidateInputAttribute to a
|
||||
controller or action.
|
||||
-->
|
||||
<pages
|
||||
validateRequest="false"
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false"/>
|
||||
<handlers>
|
||||
<remove name="BlockViewHandler"/>
|
||||
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Note: As an alternative to hand editing this file you can use the
|
||||
web admin tool to configure settings for your application. Use
|
||||
the Website->Asp.Net Configuration option in Visual Studio.
|
||||
A full list of settings and comments can be found in
|
||||
machine.config.comments usually located in
|
||||
\Windows\Microsoft.Net\Framework\v2.x\Config
|
||||
-->
|
||||
<configuration>
|
||||
<appSettings/>
|
||||
<connectionStrings>
|
||||
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>
|
||||
</connectionStrings>
|
||||
<system.web>
|
||||
<!--
|
||||
Set compilation debug="true" to insert debugging
|
||||
symbols into the compiled page. Because this
|
||||
affects performance, set this value to true only
|
||||
during development.
|
||||
-->
|
||||
<compilation debug="true" targetFramework="4.0">
|
||||
<assemblies>
|
||||
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/></assemblies>
|
||||
</compilation>
|
||||
<!--
|
||||
The <customErrors> section enables configuration
|
||||
of what to do if/when an unhandled error occurs
|
||||
during the execution of a request. Specifically,
|
||||
it enables developers to configure html error pages
|
||||
to be displayed in place of a error stack trace.
|
||||
|
||||
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
|
||||
<error statusCode="403" redirect="NoAccess.htm" />
|
||||
<error statusCode="404" redirect="FileNotFound.htm" />
|
||||
</customErrors>
|
||||
-->
|
||||
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
|
||||
<namespaces>
|
||||
<add namespace="System.Web.Mvc"/>
|
||||
<add namespace="System.Web.Mvc.Ajax"/>
|
||||
<add namespace="System.Web.Mvc.Html"/>
|
||||
<add namespace="System.Web.Routing"/>
|
||||
<add namespace="System.Linq"/>
|
||||
<add namespace="System.Collections.Generic"/>
|
||||
<add namespace="Orchard.Mvc.Html"/>
|
||||
<add namespace="Orchard.Mvc"/>
|
||||
</namespaces>
|
||||
</pages>
|
||||
<httpHandlers>
|
||||
<add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.web.extensions/>
|
||||
<!--
|
||||
The system.webServer section is required for running ASP.NET AJAX under Internet
|
||||
Information Services 7.0. It is not necessary for previous version of IIS.
|
||||
-->
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false"/>
|
||||
<modules runAllManagedModulesForAllRequests="true">
|
||||
</modules>
|
||||
<handlers>
|
||||
<remove name="MvcHttpHandler"/>
|
||||
<remove name="UrlRoutingHandler"/>
|
||||
<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
|
||||
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
@@ -8,4 +8,7 @@ description: The Modules module enables the administrator of the site to manage
|
||||
features:
|
||||
Orchard.Modules:
|
||||
Description: Standard module and feature management.
|
||||
Category: Core
|
||||
Category: Core
|
||||
Orchard.Modules.Packaging:
|
||||
Description: Standard module and feature management.
|
||||
Category: Developer
|
||||
|
@@ -45,6 +45,7 @@
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
@@ -63,6 +64,9 @@
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
<Reference Include="System.Web.Mobile" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="WindowsBase">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
@@ -70,6 +74,14 @@
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="Models\ModuleFeature.cs" />
|
||||
<Compile Include="Packaging\Commands\PackagingCommands.cs" />
|
||||
<Compile Include="Packaging\Controllers\DownloadStreamResult.cs" />
|
||||
<Compile Include="Packaging\Controllers\PackagingController.cs" />
|
||||
<Compile Include="Packaging\Services\PackageExpander.cs" />
|
||||
<Compile Include="Packaging\Services\PackageBuilder.cs" />
|
||||
<Compile Include="Packaging\Services\PackageManager.cs" />
|
||||
<Compile Include="Packaging\Services\PackageSourceManager.cs" />
|
||||
<Compile Include="Packaging\ViewModels\PackagingModulesViewModel.cs" />
|
||||
<Compile Include="ViewModels\FeaturesViewModel.cs" />
|
||||
<Compile Include="Models\Module.cs" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
@@ -88,6 +100,10 @@
|
||||
<Content Include="styles\jquery.switchable.css" />
|
||||
<Content Include="Views\Admin\Add.ascx" />
|
||||
<Content Include="Views\Admin\Index.ascx" />
|
||||
<Content Include="Views\Packaging\_Subnav.ascx" />
|
||||
<Content Include="Views\Packaging\Harvest.ascx" />
|
||||
<Content Include="Views\Packaging\Sources.ascx" />
|
||||
<Content Include="Views\Packaging\Modules.ascx" />
|
||||
<Content Include="Web.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using Orchard.Commands;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Modules.Packaging.Services;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Commands {
|
||||
[OrchardFeature("Orchard.Modules.Packaging")]
|
||||
public class PackagingCommands : DefaultOrchardCommandHandler {
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IPackageBuilder _packageBuilder;
|
||||
private readonly IPackageManager _packageManager;
|
||||
|
||||
public PackagingCommands(IExtensionManager extensionManager, IPackageBuilder packageBuilder, IPackageManager packageManager) {
|
||||
_extensionManager = extensionManager;
|
||||
_packageBuilder = packageBuilder;
|
||||
_packageManager = packageManager;
|
||||
}
|
||||
|
||||
[CommandHelp("harvest <moduleName>\r\n\t" + "Package a module into a distributable")]
|
||||
[CommandName("harvest")]
|
||||
public void PackageCreate(string moduleName) {
|
||||
var packageData = _packageManager.Harvest(moduleName);
|
||||
if (packageData.PackageStream.CanSeek)
|
||||
packageData.PackageStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
const int chunk = 512;
|
||||
var dataBuffer = new byte[3 * chunk];
|
||||
var charBuffer = new char[4 * chunk + 2];
|
||||
for (; ; ) {
|
||||
var dataCount = packageData.PackageStream.Read(dataBuffer, 0, dataBuffer.Length);
|
||||
if (dataCount <= 0)
|
||||
return;
|
||||
|
||||
var charCount = Convert.ToBase64CharArray(dataBuffer, 0, dataCount, charBuffer, 0);
|
||||
Context.Output.Write(charBuffer, 0, charCount);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelp("harvest post <moduleName> <feedUrl>\r\n\t" + "Package a module into a distributable and push it to a feed server.")]
|
||||
[CommandName("harvest post")]
|
||||
public void PackageCreate(string moduleName, string feedUrl) {
|
||||
var packageData = _packageManager.Harvest(moduleName);
|
||||
_packageManager.Push(packageData, feedUrl);
|
||||
|
||||
try {
|
||||
_packageManager.Push(packageData, feedUrl);
|
||||
Context.Output.WriteLine("Success");
|
||||
}
|
||||
catch (WebException webException) {
|
||||
var text = new StreamReader(webException.Response.GetResponseStream()).ReadToEnd();
|
||||
throw new ApplicationException(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,23 @@
|
||||
using System.IO;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Controllers {
|
||||
public class DownloadStreamResult : ActionResult {
|
||||
public string FileName { get; set; }
|
||||
public string ContentType { get; set; }
|
||||
public Stream Stream { get; set; }
|
||||
|
||||
public DownloadStreamResult(string fileName, string contentType, Stream stream) {
|
||||
FileName = fileName;
|
||||
ContentType = contentType;
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public override void ExecuteResult(ControllerContext context) {
|
||||
context.HttpContext.Response.ContentType = ContentType;
|
||||
context.HttpContext.Response.AddHeader("content-disposition", "attachment; filename=\"" + FileName + "\"");
|
||||
Stream.Seek(0, SeekOrigin.Begin);
|
||||
Stream.CopyTo(context.HttpContext.Response.OutputStream);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Modules.Packaging.Services;
|
||||
using Orchard.Modules.Packaging.ViewModels;
|
||||
using Orchard.Themes;
|
||||
using Orchard.UI.Admin;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Controllers {
|
||||
[Admin, Themed, OrchardFeature("Orchard.Modules.Packaging")]
|
||||
public class PackagingController : Controller {
|
||||
private readonly IPackageManager _packageManager;
|
||||
private readonly IPackageSourceManager _packageSourceManager;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public PackagingController(
|
||||
IPackageManager packageManager,
|
||||
IPackageSourceManager packageSourceManager,
|
||||
IExtensionManager extensionManager,
|
||||
INotifier notifier) {
|
||||
_packageManager = packageManager;
|
||||
_packageSourceManager = packageSourceManager;
|
||||
_extensionManager = extensionManager;
|
||||
_notifier = notifier;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
Localizer T { get; set; }
|
||||
|
||||
public ActionResult Index() {
|
||||
return Modules();
|
||||
}
|
||||
|
||||
public ActionResult Sources() {
|
||||
return View("Sources", new PackagingSourcesViewModel {
|
||||
Sources = _packageSourceManager.GetSources(),
|
||||
});
|
||||
}
|
||||
|
||||
public ActionResult AddSource(string url) {
|
||||
_packageSourceManager.AddSource(new PackageSource { Id = Guid.NewGuid(), FeedUrl = url });
|
||||
Update();
|
||||
return RedirectToAction("Sources");
|
||||
}
|
||||
|
||||
|
||||
public ActionResult Modules() {
|
||||
return View("Modules", new PackagingModulesViewModel {
|
||||
Modules = _packageSourceManager.GetModuleList()
|
||||
});
|
||||
}
|
||||
|
||||
public ActionResult Update() {
|
||||
_packageSourceManager.UpdateLists();
|
||||
_notifier.Information(T("List of available modules and themes is updated."));
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
public ActionResult Harvest(string extensionName, string feedUrl) {
|
||||
return View("Harvest", new PackagingHarvestViewModel {
|
||||
ExtensionName = extensionName,
|
||||
FeedUrl = feedUrl,
|
||||
Sources = _packageSourceManager.GetSources(),
|
||||
Extensions = _extensionManager.AvailableExtensions()
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Harvest(PackagingHarvestViewModel model) {
|
||||
model.Sources = _packageSourceManager.GetSources();
|
||||
model.Extensions = _extensionManager.AvailableExtensions();
|
||||
|
||||
var packageData = _packageManager.Harvest(model.ExtensionName);
|
||||
|
||||
if (string.IsNullOrEmpty(model.FeedUrl)) {
|
||||
return new DownloadStreamResult(
|
||||
packageData.ExtensionName + "-" + packageData.ExtensionVersion + ".zip",
|
||||
"application/x-package",
|
||||
packageData.PackageStream);
|
||||
}
|
||||
|
||||
if (!model.Sources.Any(src => src.FeedUrl == model.FeedUrl)) {
|
||||
ModelState.AddModelError("FeedUrl", T("May only push directly to one of the configured sources.").ToString());
|
||||
return View("Harvest", model);
|
||||
}
|
||||
|
||||
_packageManager.Push(packageData, model.FeedUrl);
|
||||
_notifier.Information(T("Harvested {0} and published onto {1}", model.ExtensionName, model.FeedUrl));
|
||||
|
||||
Update();
|
||||
|
||||
return RedirectToAction("Harvest", new { model.ExtensionName, model.FeedUrl });
|
||||
}
|
||||
|
||||
public ActionResult Install(string syndicationId) {
|
||||
var packageData = _packageManager.Download(syndicationId);
|
||||
_packageManager.Install(packageData);
|
||||
_notifier.Information(T("Installed module"));
|
||||
return RedirectToAction("Modules");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Packaging;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Services {
|
||||
public interface IPackageBuilder : IDependency {
|
||||
Stream BuildPackage(ExtensionDescriptor extensionDescriptor);
|
||||
}
|
||||
|
||||
[OrchardFeature("Orchard.Modules.Packaging")]
|
||||
public class PackageBuilder : IPackageBuilder {
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IWebSiteFolder _webSiteFolder;
|
||||
|
||||
public PackageBuilder(IExtensionManager extensionManager, IWebSiteFolder webSiteFolder) {
|
||||
_extensionManager = extensionManager;
|
||||
_webSiteFolder = webSiteFolder;
|
||||
}
|
||||
|
||||
class CreateContext {
|
||||
public Stream Stream { get; set; }
|
||||
public Package Package { get; set; }
|
||||
|
||||
public IWebSiteFolder SourceFolder { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
public string TargetPath { get; set; }
|
||||
|
||||
public XDocument Project { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public Stream BuildPackage(ExtensionDescriptor extensionDescriptor) {
|
||||
|
||||
|
||||
var context = new CreateContext();
|
||||
BeginPackage(context);
|
||||
try {
|
||||
EstablishPaths(context, _webSiteFolder, extensionDescriptor.Location, extensionDescriptor.Name);
|
||||
SetCoreProperties(context, extensionDescriptor);
|
||||
|
||||
var projectFile = extensionDescriptor.Name + ".csproj";
|
||||
if (LoadProject(context, projectFile)) {
|
||||
EmbedVirtualFile(context, projectFile, System.Net.Mime.MediaTypeNames.Text.Xml);
|
||||
EmbedProjectFiles(context, "Compile", "Content", "None", "EmbeddedResource");
|
||||
EmbedReferenceFiles(context);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
EndPackage(context);
|
||||
}
|
||||
|
||||
return context.Stream;
|
||||
}
|
||||
|
||||
private void SetCoreProperties(CreateContext context, ExtensionDescriptor extensionDescriptor) {
|
||||
var properties = context.Package.PackageProperties;
|
||||
properties.Title = extensionDescriptor.DisplayName ?? extensionDescriptor.Name;
|
||||
//properties.Subject = "";
|
||||
properties.Creator = extensionDescriptor.Author;
|
||||
properties.Keywords = extensionDescriptor.Tags;
|
||||
properties.Description = extensionDescriptor.Description;
|
||||
//properties.LastModifiedBy = "";
|
||||
//properties.Revision = "";
|
||||
//properties.LastPrinted = "";
|
||||
//properties.Created = "";
|
||||
//properties.Modified = "";
|
||||
properties.Category = extensionDescriptor.Features.Where(f => f.Name == extensionDescriptor.Name).Select(f => f.Category).FirstOrDefault();
|
||||
properties.Identifier = extensionDescriptor.Name;
|
||||
properties.ContentType = "Orchard " + extensionDescriptor.ExtensionType;
|
||||
//properties.Language = "";
|
||||
properties.Version = extensionDescriptor.Version;
|
||||
properties.ContentStatus = "";
|
||||
}
|
||||
|
||||
|
||||
private void EmbedProjectFiles(CreateContext context, params string[] itemGroupTypes) {
|
||||
var itemGroups = context.Project
|
||||
.Elements(Ns("Project"))
|
||||
.Elements(Ns("ItemGroup"));
|
||||
|
||||
foreach (var itemGroupType in itemGroupTypes) {
|
||||
var includePaths = itemGroups
|
||||
.Elements(Ns(itemGroupType))
|
||||
.Attributes("Include")
|
||||
.Select(x => x.Value);
|
||||
foreach (var includePath in includePaths) {
|
||||
EmbedVirtualFile(context, includePath, System.Net.Mime.MediaTypeNames.Application.Octet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EmbedReferenceFiles(CreateContext context) {
|
||||
var entries = context.Project
|
||||
.Elements(Ns("Project"))
|
||||
.Elements(Ns("ItemGroup"))
|
||||
.Elements(Ns("Reference"))
|
||||
.Select(reference => new {
|
||||
Include = reference.Attribute("Include"),
|
||||
HintPath = reference.Element(Ns("HintPath"))
|
||||
})
|
||||
.Where(entry => entry.Include != null);
|
||||
|
||||
foreach (var entry in entries) {
|
||||
var assemblyName = new AssemblyName(entry.Include.Value);
|
||||
var hintPath = entry.HintPath != null ? entry.HintPath.Value : null;
|
||||
|
||||
var virtualPath = "bin/" + assemblyName.Name + ".dll";
|
||||
if (context.SourceFolder.FileExists(context.SourcePath + virtualPath)) {
|
||||
EmbedVirtualFile(context, virtualPath, System.Net.Mime.MediaTypeNames.Application.Octet);
|
||||
}
|
||||
else if (hintPath != null) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private XName Ns(string localName) {
|
||||
return XName.Get(localName, "http://schemas.microsoft.com/developer/msbuild/2003");
|
||||
}
|
||||
|
||||
|
||||
static void BeginPackage(CreateContext context) {
|
||||
context.Stream = new MemoryStream();
|
||||
context.Package = Package.Open(context.Stream, FileMode.Create, FileAccess.ReadWrite);
|
||||
}
|
||||
|
||||
static void EstablishPaths(CreateContext context, IWebSiteFolder webSiteFolder, string locationPath, string moduleName) {
|
||||
context.SourceFolder = webSiteFolder;
|
||||
context.SourcePath = "~/Modules/" + moduleName + "/";
|
||||
context.TargetPath = "\\" + moduleName + "\\";
|
||||
}
|
||||
|
||||
static bool LoadProject(CreateContext context, string relativePath) {
|
||||
var virtualPath = context.SourcePath + relativePath;
|
||||
if (context.SourceFolder.FileExists(virtualPath)) {
|
||||
context.Project = XDocument.Parse(context.SourceFolder.ReadFile(context.SourcePath + relativePath));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Uri EmbedVirtualFile(CreateContext context, string relativePath, string contentType) {
|
||||
var partUri = PackUriHelper.CreatePartUri(new Uri(context.TargetPath + relativePath, UriKind.Relative));
|
||||
var packagePart = context.Package.CreatePart(partUri, contentType);
|
||||
using (var stream = packagePart.GetStream(FileMode.Create, FileAccess.Write)) {
|
||||
context.SourceFolder.CopyFileTo(context.SourcePath + relativePath, stream);
|
||||
}
|
||||
return partUri;
|
||||
}
|
||||
|
||||
static void EndPackage(CreateContext context) {
|
||||
context.Package.Close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Packaging;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Services {
|
||||
public interface IPackageExpander : IDependency {
|
||||
void ExpandPackage(Stream packageStream);
|
||||
}
|
||||
|
||||
[OrchardFeature("Orchard.Modules.Packaging")]
|
||||
public class PackageExpander : IPackageExpander {
|
||||
private const string ContentTypePrefix = "Orchard ";
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IWebSiteFolder _webSiteFolder;
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
|
||||
public PackageExpander(
|
||||
IExtensionManager extensionManager,
|
||||
IWebSiteFolder webSiteFolder,
|
||||
IVirtualPathProvider virtualPathProvider) {
|
||||
_extensionManager = extensionManager;
|
||||
_webSiteFolder = webSiteFolder;
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
}
|
||||
|
||||
class ExpandContext {
|
||||
public Stream Stream { get; set; }
|
||||
public Package Package { get; set; }
|
||||
|
||||
public string ExtensionName { get; set; }
|
||||
public string ExtensionType { get; set; }
|
||||
|
||||
public string TargetPath { get; set; }
|
||||
|
||||
public string SourcePath { get; set; }
|
||||
|
||||
public XDocument Project { get; set; }
|
||||
}
|
||||
|
||||
public void ExpandPackage(Stream packageStream) {
|
||||
var context = new ExpandContext();
|
||||
BeginPackage(context, packageStream);
|
||||
try {
|
||||
GetCoreProperties(context);
|
||||
EstablishPaths(context, _virtualPathProvider);
|
||||
|
||||
var projectFile = context.ExtensionName + ".csproj";
|
||||
if (LoadProject(context, projectFile)) {
|
||||
ExtractFile(context, projectFile);
|
||||
ExtractProjectFiles(context, "Compile", "Content", "None", "EmbeddedResource");
|
||||
ExtractReferenceFiles(context);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
EndPackage(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractFile(ExpandContext context, string relativePath) {
|
||||
var partUri = PackUriHelper.CreatePartUri(new Uri(context.SourcePath + relativePath, UriKind.Relative));
|
||||
var packagePart = context.Package.GetPart(partUri);
|
||||
using (var packageStream = packagePart.GetStream(FileMode.Open, FileAccess.Read)) {
|
||||
var filePath = Path.Combine(context.TargetPath, relativePath);
|
||||
var folderPath = Path.GetDirectoryName(filePath);
|
||||
if (!Directory.Exists(folderPath))
|
||||
Directory.CreateDirectory(folderPath);
|
||||
|
||||
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read)) {
|
||||
packageStream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractProjectFiles(ExpandContext context, params string[] itemGroupTypes) {
|
||||
var itemGroups = context.Project
|
||||
.Elements(Ns("Project"))
|
||||
.Elements(Ns("ItemGroup"));
|
||||
|
||||
foreach (var itemGroupType in itemGroupTypes) {
|
||||
var includePaths = itemGroups
|
||||
.Elements(Ns(itemGroupType))
|
||||
.Attributes("Include")
|
||||
.Select(x => x.Value);
|
||||
foreach (var includePath in includePaths) {
|
||||
ExtractFile(context, includePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractReferenceFiles(ExpandContext context) {
|
||||
var entries = context.Project
|
||||
.Elements(Ns("Project"))
|
||||
.Elements(Ns("ItemGroup"))
|
||||
.Elements(Ns("Reference"))
|
||||
.Select(reference => new {
|
||||
Include = reference.Attribute("Include"),
|
||||
HintPath = reference.Element(Ns("HintPath"))
|
||||
})
|
||||
.Where(entry => entry.Include != null);
|
||||
|
||||
foreach (var entry in entries) {
|
||||
var assemblyName = new AssemblyName(entry.Include.Value);
|
||||
var hintPath = entry.HintPath != null ? entry.HintPath.Value : null;
|
||||
|
||||
var virtualPath = "bin/" + assemblyName.Name + ".dll";
|
||||
if (PartExists(context, virtualPath)) {
|
||||
ExtractFile(context, virtualPath);
|
||||
}
|
||||
else if (hintPath != null) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool PartExists(ExpandContext context, string relativePath) {
|
||||
var projectUri = PackUriHelper.CreatePartUri(new Uri(context.SourcePath + relativePath, UriKind.Relative));
|
||||
return context.Package.PartExists(projectUri);
|
||||
}
|
||||
|
||||
|
||||
private XName Ns(string localName) {
|
||||
return XName.Get(localName, "http://schemas.microsoft.com/developer/msbuild/2003");
|
||||
}
|
||||
private static bool LoadProject(ExpandContext context, string relativePath) {
|
||||
var projectUri = PackUriHelper.CreatePartUri(new Uri(context.SourcePath + relativePath, UriKind.Relative));
|
||||
if (!context.Package.PartExists(projectUri))
|
||||
return false;
|
||||
var part = context.Package.GetPart(projectUri);
|
||||
using (var stream = part.GetStream(FileMode.Open, FileAccess.Read)) {
|
||||
context.Project = XDocument.Load(stream);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BeginPackage(ExpandContext context, Stream packageStream) {
|
||||
if (packageStream.CanSeek) {
|
||||
context.Stream = packageStream;
|
||||
}
|
||||
else {
|
||||
context.Stream = new MemoryStream();
|
||||
packageStream.CopyTo(context.Stream);
|
||||
}
|
||||
context.Package = Package.Open(context.Stream, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
private void EndPackage(ExpandContext context) {
|
||||
context.Package.Close();
|
||||
}
|
||||
|
||||
private void GetCoreProperties(ExpandContext context) {
|
||||
context.ExtensionName = context.Package.PackageProperties.Identifier;
|
||||
|
||||
var contentType = context.Package.PackageProperties.ContentType;
|
||||
if (contentType.StartsWith(ContentTypePrefix))
|
||||
context.ExtensionType = contentType.Substring(ContentTypePrefix.Length);
|
||||
}
|
||||
|
||||
private void EstablishPaths(ExpandContext context, IVirtualPathProvider virtualPathProvider) {
|
||||
context.SourcePath = "\\" + context.ExtensionName + "\\";
|
||||
if (context.ExtensionType == "Theme") {
|
||||
context.TargetPath = virtualPathProvider.MapPath("~/Themes-temp/" + context.ExtensionName);
|
||||
}
|
||||
else if (context.ExtensionType == "Module") {
|
||||
context.TargetPath = virtualPathProvider.MapPath("~/Modules-temp/" + context.ExtensionName);
|
||||
}
|
||||
else {
|
||||
throw new ApplicationException("Unknown extension type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Packaging;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using Orchard.Environment.Extensions;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Services {
|
||||
|
||||
public class PackageData {
|
||||
public string ExtensionName { get; set; }
|
||||
public string ExtensionVersion { get; set; }
|
||||
|
||||
public Stream PackageStream { get; set; }
|
||||
}
|
||||
|
||||
public interface IPackageManager : IDependency {
|
||||
PackageData Harvest(string extensionName);
|
||||
PackageData Download(string feedItemId);
|
||||
|
||||
void Push(PackageData packageData, string feedUrl);
|
||||
void Install(PackageData packageData);
|
||||
}
|
||||
|
||||
[OrchardFeature("Orchard.Modules.Packaging")]
|
||||
public class PackageManager : IPackageManager {
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IPackageSourceManager _packageSourceManager;
|
||||
private readonly IPackageBuilder _packageBuilder;
|
||||
private readonly IPackageExpander _packageExpander;
|
||||
|
||||
public PackageManager(
|
||||
IExtensionManager extensionManager,
|
||||
IPackageSourceManager packageSourceManager,
|
||||
IPackageBuilder packageBuilder,
|
||||
IPackageExpander packageExpander) {
|
||||
_extensionManager = extensionManager;
|
||||
_packageSourceManager = packageSourceManager;
|
||||
_packageBuilder = packageBuilder;
|
||||
_packageExpander = packageExpander;
|
||||
}
|
||||
|
||||
public PackageData Harvest(string extensionName) {
|
||||
var extensionDescriptor = _extensionManager.AvailableExtensions().FirstOrDefault(x => x.Name == extensionName);
|
||||
if (extensionDescriptor == null)
|
||||
return null;
|
||||
return new PackageData {
|
||||
ExtensionName = extensionDescriptor.Name,
|
||||
ExtensionVersion = extensionDescriptor.Version,
|
||||
PackageStream = _packageBuilder.BuildPackage(extensionDescriptor),
|
||||
};
|
||||
}
|
||||
|
||||
public void Push(PackageData packageData, string feedUrl) {
|
||||
|
||||
var request = WebRequest.Create(feedUrl);
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/x-package";
|
||||
using (var requestStream = request.GetRequestStream()) {
|
||||
packageData.PackageStream.Seek(0, SeekOrigin.Begin);
|
||||
packageData.PackageStream.CopyTo(requestStream);
|
||||
}
|
||||
|
||||
using (request.GetResponse()) {
|
||||
// forces request and disposes results
|
||||
}
|
||||
}
|
||||
|
||||
public PackageData Download(string feedItemId) {
|
||||
var entry = _packageSourceManager.GetModuleList().Single(x => x.SyndicationItem.Id == feedItemId);
|
||||
var request = WebRequest.Create(entry.PackageStreamUri);
|
||||
using (var response = request.GetResponse()) {
|
||||
using (var responseStream = response.GetResponseStream()) {
|
||||
var stream = new MemoryStream();
|
||||
responseStream.CopyTo(stream);
|
||||
var package = Package.Open(stream);
|
||||
try {
|
||||
return new PackageData {
|
||||
ExtensionName = package.PackageProperties.Identifier,
|
||||
ExtensionVersion = package.PackageProperties.Version,
|
||||
PackageStream = stream
|
||||
};
|
||||
}
|
||||
finally {
|
||||
package.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Install(PackageData packageData) {
|
||||
_packageExpander.ExpandPackage(packageData.PackageStream);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.ServiceModel.Syndication;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.FileSystems.AppData;
|
||||
|
||||
namespace Orchard.Modules.Packaging.Services {
|
||||
public interface IPackageSourceManager : IDependency {
|
||||
IEnumerable<PackageSource> GetSources();
|
||||
void AddSource(PackageSource source);
|
||||
void RemoveSource(Guid id);
|
||||
void UpdateLists();
|
||||
|
||||
IEnumerable<PackageEntry> GetModuleList();
|
||||
}
|
||||
|
||||
public class PackageSource {
|
||||
public Guid Id { get; set; }
|
||||
public string FeedUrl { get; set; }
|
||||
}
|
||||
|
||||
public class PackageEntry {
|
||||
public PackageSource Source { get; set; }
|
||||
public SyndicationFeed SyndicationFeed { get; set; }
|
||||
public SyndicationItem SyndicationItem { get; set; }
|
||||
public string PackageStreamUri { get; set; }
|
||||
}
|
||||
|
||||
|
||||
static class AtomExtensions {
|
||||
public static string Atom(this XElement entry, string localName) {
|
||||
var element = entry.Element(AtomXName(localName));
|
||||
return element != null ? element.Value : null;
|
||||
}
|
||||
|
||||
public static XName AtomXName(string localName) {
|
||||
return XName.Get(localName, "http://www.w3.org/2005/Atom");
|
||||
}
|
||||
}
|
||||
|
||||
[OrchardFeature("Orchard.Modules.Packaging")]
|
||||
public class PackageSourceManager : IPackageSourceManager {
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private static readonly XmlSerializer _sourceSerializer = new XmlSerializer(typeof(List<PackageSource>), new XmlRootAttribute("Sources"));
|
||||
|
||||
public PackageSourceManager(IAppDataFolder appDataFolder) {
|
||||
_appDataFolder = appDataFolder;
|
||||
}
|
||||
|
||||
static string GetSourcesPath() {
|
||||
return ".Packaging/Sources.xml";
|
||||
}
|
||||
static string GetFeedCachePath(PackageSource source) {
|
||||
return ".Packaging/Feed." + source.Id.ToString("n") + ".xml";
|
||||
}
|
||||
|
||||
public IEnumerable<PackageSource> GetSources() {
|
||||
var text = _appDataFolder.ReadFile(GetSourcesPath());
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return Enumerable.Empty<PackageSource>();
|
||||
|
||||
var textReader = new StringReader(_appDataFolder.ReadFile(GetSourcesPath()));
|
||||
return (IEnumerable<PackageSource>)_sourceSerializer.Deserialize(textReader);
|
||||
}
|
||||
|
||||
void SaveSources(IEnumerable<PackageSource> sources) {
|
||||
var textWriter = new StringWriter();
|
||||
_sourceSerializer.Serialize(textWriter, sources.ToList());
|
||||
|
||||
_appDataFolder.CreateFile(GetSourcesPath(), textWriter.ToString());
|
||||
}
|
||||
|
||||
public void AddSource(PackageSource source) {
|
||||
UpdateSource(source);
|
||||
SaveSources(GetSources().Concat(new[] { source }));
|
||||
}
|
||||
|
||||
public void RemoveSource(Guid id) {
|
||||
SaveSources(GetSources().Where(x => x.Id != id));
|
||||
}
|
||||
|
||||
public void UpdateLists() {
|
||||
foreach (var source in GetSources()) {
|
||||
UpdateSource(source);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSource(PackageSource source) {
|
||||
var feed = XDocument.Load(source.FeedUrl, LoadOptions.PreserveWhitespace);
|
||||
_appDataFolder.CreateFile(GetFeedCachePath(source), feed.ToString(SaveOptions.DisableFormatting));
|
||||
}
|
||||
|
||||
|
||||
static XName Atom(string localName) {
|
||||
return AtomExtensions.AtomXName(localName);
|
||||
}
|
||||
|
||||
static IEnumerable<T> Unit<T>(T t) where T : class {
|
||||
return t != null ? new[] { t } : Enumerable.Empty<T>();
|
||||
}
|
||||
static IEnumerable<T2> Bind<T, T2>(T t, Func<T, IEnumerable<T2>> f) where T : class {
|
||||
return Unit(t).SelectMany(f);
|
||||
}
|
||||
|
||||
private SyndicationFeed ParseFeed(string content) {
|
||||
var formatter = new Atom10FeedFormatter<SyndicationFeed>();
|
||||
formatter.ReadFrom(XmlReader.Create(new StringReader(content)));
|
||||
return formatter.Feed;
|
||||
}
|
||||
|
||||
public IEnumerable<PackageEntry> GetModuleList() {
|
||||
var packageInfos = GetSources()
|
||||
.SelectMany(
|
||||
source =>
|
||||
Bind(ParseFeed(_appDataFolder.ReadFile(GetFeedCachePath(source))),
|
||||
feed =>
|
||||
feed.Items.SelectMany(
|
||||
item =>
|
||||
Unit(new PackageEntry {
|
||||
Source = source,
|
||||
SyndicationFeed = feed,
|
||||
SyndicationItem = item,
|
||||
PackageStreamUri = item.Links.Single().GetAbsoluteUri().AbsoluteUri,
|
||||
}))));
|
||||
|
||||
|
||||
return packageInfos.ToArray();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Modules.Packaging.Services;
|
||||
|
||||
namespace Orchard.Modules.Packaging.ViewModels {
|
||||
public class PackagingModulesViewModel {
|
||||
public IEnumerable<PackageEntry> Modules { get; set; }
|
||||
}
|
||||
public class PackagingSourcesViewModel {
|
||||
public IEnumerable<PackageSource> Sources { get; set; }
|
||||
}
|
||||
public class PackagingHarvestViewModel {
|
||||
public IEnumerable<PackageSource> Sources { get; set; }
|
||||
public IEnumerable<ExtensionDescriptor> Extensions { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ExtensionName { get; set; }
|
||||
|
||||
public string FeedUrl { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Modules.Packaging.ViewModels.PackagingHarvestViewModel>" %>
|
||||
<%@ Import Namespace="Orchard.Mvc.Html" %>
|
||||
<h1>
|
||||
<%: Html.TitleForPage(T("Packaging").ToString(), T("Harvest Packages").ToString())%></h1>
|
||||
<%: Html.Partial("_Subnav") %>
|
||||
|
||||
<%using (Html.BeginFormAntiForgeryPost()) {%>
|
||||
<%: Html.ValidationSummary(T("Package creation was unsuccessful. Please correct the errors and try again.").ToString()) %>
|
||||
<%foreach (var group in Model.Extensions.Where(x => !x.Location.StartsWith("~/Core")).GroupBy(x => x.ExtensionType)) {%>
|
||||
<fieldset>
|
||||
<legend>Harvest
|
||||
<%:group.Key %></legend>
|
||||
<ul>
|
||||
<%foreach (var item in group) {%>
|
||||
<li>
|
||||
<label>
|
||||
<%:Html.RadioButtonFor(m=>m.ExtensionName, item.Name, new Dictionary<string, object>{{"id",item.Name}}) %>
|
||||
<%:item.DisplayName%></label></li><%
|
||||
}%></ul>
|
||||
<%} %>
|
||||
<%: Html.ValidationMessageFor(m => m.ExtensionName)%>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<%: Html.LabelFor(m=>m.FeedUrl)%>
|
||||
<%: Html.DropDownListFor(m => m.FeedUrl, new[]{new SelectListItem{Text="Download",Value=""}}.Concat( Model.Sources.Select(x => new SelectListItem { Text = "Push to " + x.FeedUrl, Value = x.FeedUrl })))%>
|
||||
<%: Html.ValidationMessageFor(m=>m.FeedUrl) %>
|
||||
</fieldset>
|
||||
<input type="submit" value="Harvest" />
|
||||
<%} %>
|
@@ -0,0 +1,12 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Modules.Packaging.ViewModels.PackagingModulesViewModel>" %>
|
||||
<%@ Import Namespace="Orchard.Mvc.Html" %>
|
||||
<h1>
|
||||
<%: Html.TitleForPage(T("Packaging").ToString(), T("Browse Packages").ToString())%></h1>
|
||||
<%: Html.Partial("_Subnav") %>
|
||||
|
||||
<p><%:Html.ActionLink("Update List", "Update") %></p>
|
||||
<ul>
|
||||
<%foreach (var item in Model.Modules) {%><li><a href="<%:item.PackageStreamUri%>">
|
||||
<%:item.SyndicationItem.Title.Text%></a> [<%:Html.ActionLink("Install", "Install", new RouteValueDictionary {{"SyndicationId",item.SyndicationItem.Id}})%>]
|
||||
</li><%
|
||||
}%></ul>
|
@@ -0,0 +1,15 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Modules.Packaging.ViewModels.PackagingSourcesViewModel>" %>
|
||||
<%@ Import Namespace="Orchard.Mvc.Html" %>
|
||||
<h1>
|
||||
<%: Html.TitleForPage(T("Packaging").ToString(), T("Edit Sources").ToString())%></h1>
|
||||
<%: Html.Partial("_Subnav") %>
|
||||
|
||||
<ul>
|
||||
<%foreach (var item in Model.Sources) {%><li>
|
||||
<%:Html.Link(item.FeedUrl, item.FeedUrl)%></li><%
|
||||
}%></ul>
|
||||
<%using (Html.BeginFormAntiForgeryPost(Url.Action("AddSource"))) {%>
|
||||
Url:
|
||||
<%:Html.TextBox("url") %>
|
||||
<input type="submit" value="Add Source" />
|
||||
<%} %>
|
@@ -0,0 +1,8 @@
|
||||
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
|
||||
<p>
|
||||
<%:Html.ActionLink("Browse Repository Packages", "Index") %>
|
||||
•
|
||||
<%:Html.ActionLink("Harvest Local Packages", "Harvest") %>
|
||||
•
|
||||
<%:Html.ActionLink("Edit Repository Sources", "Sources") %>
|
||||
</p>
|
Reference in New Issue
Block a user