Orchard CMS: сообщаем поисковым системам о добавлении новых статей

Программирование

Tagged Under : , , , , ,

В этот раз я попытаюсь рассмотреть процесс создания модуля для Orchard CMS, который будет пинговать поисковые системы (google, yandex, yahoo, bing, ask) сообщая им о том, что обновилась информация на сайте и нужно проверить файл sitemap.xml.

Функционирование модуля можно описать кратко следующим образом: создадим ContentPart (PingContentPart), которую нужно будет присоединять к типам контента (ContentType), при добавлении которых нужно пинговать сервисы; для пинга придётся реализовать небольшой класс; поисковые сервисы (адреса которые нужно пинговать) будут жёстко прописаны в коде.

Прежде всего начнём с создания заготовки модуля:

orchard.exe codegen module SitemapPing

Затем тут же добавляем Migration.cs

orchard.exe codegen datamigration SitemapPing

Открываем проект модуля и изменяем Migration.cs следующим образом:

public int Create() {

    SchemaBuilder.CreateTable("SitemapPingRecord", table => table.ContentPartRecord());
        SchemaBuilder.CreateTable("SitemapPingSettingsRecord", table => table.Column("Id", DbType.Int32, column => column.PrimaryKey().Identity())
                .Column("LastUpdateTime", DbType.DateTime, column => column.Nullable()));

    ContentDefinitionManager.AlterPartDefinition("SitemapPingPart", cfg => cfg.Attachable());

    return 1;
}

В папке Models создаём два класса пустышки: SitemapPingRecord

public class SitemapPingRecord: ContentPartRecord
{
}

SitemapPingPart

public class SitemapPingPart: ContentPart<SitemapPingRecord>
{
}

И служебный класс (в нём будем хранить время последнего пинга к сервисам, чтобы не пинговать чаще чем раз в час)

public class SitemapPingSettingsRecord
{
    public virtual int Id { get; set; }
    public virtual DateTime LastUpdateTime { get; set; }
}

Добавляем папку Services и добавляем интерфейс и класс, соответственно, IPingService и PingService.

public interface IPingService: IDependency
{
    void Ping();
}
public class PingService : IPingService
{
    const int pingTimeout = 5000;

    const string GooglePingUrl = "http://www.google.com/webmasters/sitemaps/ping?sitemap={0}";
    const string YandexPingUrl = "http://ping.blogs.yandex.ru/ping?sitemap={0}";
    const string YahooPingUrl = "http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap={0}";
    const string BingPingUrl = "http://www.bing.com/webmaster/ping.aspx?siteMap={0}";
    const string AskPingUrl = "http://submissions.ask.com/ping?sitemap={0}";

    IContentManager _contentManager;
    IRepository<SitemapPingSettingsRecord> _repository;

    public PingService(IContentManager contentManager, IRepository<SitemapPingSettingsRecord> repository)
    {
        _contentManager = contentManager;
        _repository = repository;
    }

    public void Ping()
    {
        string siteSitemapUrl = string.Format("http://{0}/sitemap.xml", HttpContext.Current.Request.Url.Host);

        bool IsNeedUpdate = false;
        var settings = _repository.Table.FirstOrDefault();

        if (settings == null)
        {
            IsNeedUpdate = true;
            _repository.Create(new SitemapPingSettingsRecord { LastUpdateTime = DateTime.Now });
        }
        else
            if (Math.Abs(settings.LastUpdateTime.Subtract(DateTime.Now).TotalHours) >= 1)
            {
                IsNeedUpdate = true;
                settings.LastUpdateTime = DateTime.Now;
            }

        if (IsNeedUpdate)
        {
            SendPing(string.Format(GooglePingUrl, siteSitemapUrl));
            SendPing(string.Format(YahooPingUrl, siteSitemapUrl));
            SendPing(string.Format(YandexPingUrl, siteSitemapUrl));
            SendPing(string.Format(BingPingUrl, siteSitemapUrl));
            SendPing(string.Format(AskPingUrl, siteSitemapUrl));
        }

    }

    private void SendPing(string pingServiceUrl)
    {
        HttpWebRequest pingRequest = (HttpWebRequest)WebRequest.Create(pingServiceUrl);
        pingRequest.Method = "GET";
        pingRequest.Timeout = pingTimeout;

        using (HttpWebResponse pingResponse = (HttpWebResponse)pingRequest.GetResponse())
        {
        }
    }
}

Добавляем хендлер

public class SitemapPingHandler: ContentHandler
{
    IPingService _pingService;
    public SitemapPingHandler(IRepository<SitemapPingRecord> repository, IPingService pingService)
    {
        _pingService = pingService;
        Filters.Add(StorageFilter.For(repository));

        OnPublished<SitemapPingPart>((context, part) => { // когда нажали кнопку Publish и опубликовали версию
           
            if ((context.PreviousItemVersionRecord == null && context.PublishingItemVersionRecord.Published) ||
                (context.PreviousItemVersionRecord.Published == false && context.PublishingItemVersionRecord.Published))
            {
                                // сначала, когда заполняем Заголовок (Title) RoutePart идёт ajax-запрос, при том, что ничего не публикуется всё равно отрабатывает OnPublished, поэтому вставляем нижележащие условия, чтобы выделить "настоящий" момент публикации
                var route = context.ContentItem.As<RoutePart>();
                if(route!=null)
                    if (!string.IsNullOrEmpty(route.Slug.Trim()))
                    {
                        _pingService.Ping();
                    }
            }
        });
    }
}

И, наконец, добавляем driver:

public class SitemapPingDriver: ContentPartDriver<SitemapPingPart>
{        
}

Создаём пакет

orchard.exe package create SitemapPing f:

Вот и всё, теперь при публикации записей с ContentType, к которым присоединена SitemapPingPart, будет происходить пинг поисковых сервисов.

Исходники могут немного отличаться от приведённого кода.
Пакет на сайте Orchard

OAuth + ASP.NET (Часть 1): авторизуемся через twitter, google и yahoo по протоколу OAuth 1.0

Программирование, Проекты

Tagged Under : , , , , , , , ,

Собственно, понадобилось сделать авторизацию через аккаунты различных популярных сервисов: twitter, facebook, mail.ru, google, yandex и по возможности ещё каких-нибудь. Так как я являюсь ярым сторонником подхода: если есть достаточно времени, то лучше сделать самому, – я решил реализовать это самостоятельно: изобрести велосипед в очередной раз.

Функционал будет минимальным: пройти авторизацию, получить маркер доступа (access_token) и идентификатор пользователя, ник, опционально что-нибудь ещё, например, email.

Итак, начиная с этой статьи, посвященной авторизации через twitter, google и yahoo (взят для дополнительного примера), используя и постигая OAuth 1.0, я попробую начать серию статей об OAuth-авторизации (в том числе и версии протокола 2.0 с отдельным классом и примерами для mail.ru, yandex’а, фейсбука и т.д.) через различные сервисы, поддерживающие её. При этом результатом будет небольшая библиотека с описанной функциональностью.
Читать дальше »

Используем goo.gl в проектах на ASP.NET

Программирование

Tagged Under : , ,

Частенько приходится делать так называемую «интеграцию» с социальными сервисами, в том числе и с твиттером. Такая интеграция в большинстве своём представляет собой перенос названия статьи, новости или чего-то другого и ссылки на неё в твиттер.
Как все, наверное, помнят там стоит ограничение на 140 символов, так что необходимо бороться за каждый символ и тут нам понадобится сервис коротких ссылок.
Я приведу пример использования goo.gl на ASP.NET сайте.
Читать дальше »

Поиск от google на ASP.NET сайте

Программирование

Tagged Under : , ,

Совсем недавно возникла необходимость внедрить на сайт google’овый поиск, с javascript’ом, несмотря на всю его прелесть, заморачиваться не хотелось, да и кастомизировать это всё дело (результаты и др.) не хотелось, поэтому решил написать небольшой класс.
Читать дальше »

Скачать книгу с books.google.com – миф или реальность?

Разное

Tagged Under :

Потребовалось найти книгу в электронном виде: жене для допуска к кандидатскому экзамену необходимо прочитать и перевести. Нашлась в соответствующем сервисе гугла. Всё бы ничего, но нужна была распечатка переводимого текста, да и читать 200 с лихом страниц с монитора компьютера как-то не очень. Читать дальше »