예제 #1
0
        public async Task <UserMessageContract> PostNewMessage(int id, UserMessageContract contract)
        {
            var mySettingsUrl = VocaUriBuilder.CreateAbsolute("User/MySettings").ToString();
            var messagesUrl   = VocaUriBuilder.CreateAbsolute("User/Messages").ToString();

            return(await queries.SendMessage(contract, mySettingsUrl, messagesUrl));
        }
예제 #2
0
        public async Task <ActionResult> LoginTwitterComplete(string returnUrl)
        {
            var cookie = await HttpContext.AuthenticateAsync(AuthenticationConstants.ExternalCookie);

            var accessToken = cookie.Principal.FindFirst(TwitterClaimTypes.AccessToken).Value;
            var culture     = WebHelper.GetInterfaceCultureName(Request);
            var user        = Service.CheckTwitterAuthentication(accessToken, Hostname, culture);

            if (user is null)
            {
                int.TryParse(cookie.Principal.FindFirst("urn:twitter:userid").Value, out var twitterId);
                var twitterName = cookie.Principal.FindFirst("urn:twitter:screenname").Value;
                return(View(new RegisterOpenAuthModel(accessToken, twitterName, twitterId, twitterName)));
            }

            await HandleCreateAsync(user);

            await HttpContext.SignOutAsync(AuthenticationConstants.ExternalCookie);

            var targetUrl = !string.IsNullOrEmpty(returnUrl)
                                ? VocaUriBuilder.AbsoluteFromUnknown(returnUrl, preserveAbsolute: true)
                                : Url.Action("Index", "Home");

            return(Redirect(targetUrl));
        }
예제 #3
0
        private string GetUrl(string basePart, EntryType entryType, int id)
        {
            string relative;

            switch (entryType)
            {
            case EntryType.Album:
                relative = string.Format("Al/{0}", id);
                break;

            case EntryType.Artist:
                relative = string.Format("Ar/{0}", id);
                break;

            case EntryType.Song:
                relative = string.Format("S/{0}", id);
                break;

            default:
                relative = string.Format("{0}/Details/{1}", entryType, id);
                break;
            }

            return(VocaUriBuilder.MergeUrls(basePart, relative));
        }
예제 #4
0
        public FeedResult Feed(IndexRouteParams indexParams)
        {
            WebHelper.VerifyUserAgent(Request);

            var pageSize    = (indexParams.pageSize.HasValue ? Math.Min(indexParams.pageSize.Value, 30) : 30);
            var sortRule    = indexParams.sort ?? SongSortRule.Name;
            var timeFilter  = DateTimeUtils.ParseFromSimpleString(indexParams.since);
            var filter      = indexParams.filter;
            var songType    = indexParams.songType ?? SongType.Unspecified;
            var draftsOnly  = indexParams.draftsOnly ?? false;
            var matchMode   = indexParams.matchMode ?? NameMatchMode.Auto;
            var onlyWithPVs = indexParams.onlyWithPVs ?? false;
            var minScore    = indexParams.minScore ?? 0;

            var queryParams = new SongQueryParams(filter,
                                                  songType != SongType.Unspecified ? new[] { songType } : new SongType[] { },
                                                  0, pageSize, draftsOnly, false, matchMode, sortRule, false, false, null)
            {
                TimeFilter  = timeFilter,
                OnlyWithPVs = onlyWithPVs,
                ArtistId    = indexParams.artistId ?? 0,
                MinScore    = minScore,
            };

            var result = Service.FindWithThumbPreferNotNico(queryParams);

            var fac  = new SongFeedFactory();
            var feed = fac.Create(result.Items,
                                  VocaUriBuilder.CreateAbsolute(Url.Action("Index", indexParams)),
                                  song => RenderPartialViewToString("SongItem", song),
                                  song => Url.Action("Details", new { id = song.Id }));

            return(new FeedResult(new Atom10FeedFormatter(feed)));
        }
예제 #5
0
        public ActionResult OEmbed(string url, int maxwidth = 570, int maxheight = 400, DataFormat format = DataFormat.Json)
        {
            if (string.IsNullOrEmpty(url))
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "URL not specified"));
            }

            var route      = new RouteInfo(new Uri(url), AppConfig.HostAddress).RouteData;
            var controller = route.Values["controller"].ToString().ToLowerInvariant();

            if (controller != "song" && controller != "s")
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "Only song embeds are supported"));
            }

            int id;

            if (controller == "s")
            {
                var match = Regex.Match(route.Values["action"].ToString(), @"(\d+)");
                id = int.Parse(match.Groups[1].Value);
            }
            else
            {
                id = int.Parse(route.Values["id"].ToString());
            }

            var song = Services.Songs.GetSong(id);
            var html = string.Format("<iframe src=\"{0}\" width=\"{1}\" height=\"{2}\"></iframe>",
                                     VocaUriBuilder.CreateAbsolute(Url.Action("EmbedSong", new { songId = id })), maxwidth, maxheight);

            return(Object(new SongOEmbedResponse(song, maxwidth, maxheight, html), format));
        }
예제 #6
0
        /// <summary>
        /// Converts URL to absolute (with scheme and domain), if possible.
        /// External URLs cannot be converted.
        /// </summary>
        /// <returns>Absolute URL. Cannot be null.</returns>
        /// <exception cref="NotSupportedException">URL cannot be converted to absolute.</exception>
        public VocaDbUrl ToAbsolute()
        {
            switch (Kind)
            {
            case UriKind.Absolute:
                return(this);

            case UriKind.Relative when Domain == UrlDomain.Main:
                return(new VocaDbUrl(VocaUriBuilder.Absolute(Url), Domain, UriKind.Absolute));

            case UriKind.Relative when Domain == UrlDomain.Static:
                return(new VocaDbUrl(VocaUriBuilder.StaticResource(Url), Domain, UriKind.Absolute));

            case UriKind.RelativeOrAbsolute when Domain == UrlDomain.Main:
                return(new VocaDbUrl(VocaUriBuilder.AbsoluteFromUnknown(Url, true), Domain, UriKind.Absolute));

            case UriKind.Relative when Domain == UrlDomain.External:
            case UriKind.RelativeOrAbsolute when Domain == UrlDomain.Static:
            case UriKind.RelativeOrAbsolute when Domain == UrlDomain.External:
                throw new NotSupportedException($"No way to convert to absolute URL: {DebugString}");

            default:
                throw new InvalidOperationException(DebugString);
            }
        }
예제 #7
0
        public ActionResult OEmbed(string url, int maxwidth = 570, int maxheight = 400, DataFormat format = DataFormat.Json)
        {
            if (string.IsNullOrEmpty(url))
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "URL must be specified"));
            }

            var entryId = entryUrlParser.Parse(url);

            if (entryId.IsEmpty)
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "Invalid URL"));
            }

            if (entryId.EntryType != EntryType.Song)
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "Only song embeds are supported"));
            }

            var id = entryId.Id;

            var song = songService.GetSong(entryId.Id);
            var html = string.Format("<iframe src=\"{0}\" width=\"{1}\" height=\"{2}\"></iframe>",
                                     VocaUriBuilder.CreateAbsolute(Url.Action("EmbedSong", new { songId = id })), maxwidth, maxheight);

            return(Object(new SongOEmbedResponse(song, maxwidth, maxheight, html), format));
        }
예제 #8
0
 public override string GetThumbUrlById(string id)
 {
     if (LocalFileManager.IsImage(id))
     {
         return(VocaUriBuilder.StaticResource("/media-thumb/" + id));
     }
     return(string.Empty);
 }
예제 #9
0
        public ActionResult Login(LoginModel model)
        {
            if (ModelState.IsValid)
            {
                var host    = WebHelper.GetRealHost(Request);
                var culture = WebHelper.GetInterfaceCultureName(Request);
                var result  = Data.CheckAuthentication(model.UserName, model.Password, host, culture, true);

                if (!result.IsOk)
                {
                    ModelState.AddModelError("", ViewRes.User.LoginStrings.WrongPassword);

                    if (result.Error == LoginError.AccountPoisoned)
                    {
                        ipRuleManager.TempBannedIPs.Add(host);
                    }
                }
                else
                {
                    var user = result.User;

                    TempData.SetSuccessMessage(string.Format(ViewRes.User.LoginStrings.Welcome, user.Name));
                    FormsAuthentication.SetAuthCookie(user.Name, model.KeepLoggedIn);

                    var    redirectUrl = FormsAuthentication.GetRedirectUrl(model.UserName, true);
                    string targetUrl;

                    // TODO: should not allow redirection to URLs outside the site
                    if (!string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        targetUrl = model.ReturnUrl;
                    }
                    else if (!string.IsNullOrEmpty(redirectUrl))
                    {
                        targetUrl = redirectUrl;
                    }
                    else
                    {
                        targetUrl = Url.Action("Index", "Home");
                    }

                    if (model.ReturnToMainSite)
                    {
                        targetUrl = VocaUriBuilder.AbsoluteFromUnknown(targetUrl, preserveAbsolute: true, ssl: false);
                    }

                    return(Redirect(targetUrl));
                }
            }

            if (model.ReturnToMainSite)
            {
                SaveErrorsToTempData();
                return(Redirect(VocaUriBuilder.Absolute(Url.Action("Login", new { model.ReturnUrl, model.SecureLogin }), false)));
            }

            return(View(model));
        }
예제 #10
0
        public ActionResult Create(RegisterModel model)
        {
            string restrictedErr = "Sorry, access from your host is restricted. It is possible this restriction is no longer valid. If you think this is the case, please contact support.";

            if (!ModelState.IsValidField("Extra"))
            {
                log.Warn(string.Format("An attempt was made to fill the bot decoy field from {0}.", Hostname));
                ipRuleManager.TempBannedIPs.Add(Hostname);
                return(View(model));
            }

            if (config.SiteSettings.SignupsDisabled)
            {
                ModelState.AddModelError(string.Empty, "Signups are disabled");
            }

            if (!ReCaptcha.Validate(ConfigurationManager.AppSettings["ReCAPTCHAKey"]))
            {
                var captchaResponse = Request.Params["recaptcha_response_field"] ?? string.Empty;
                ErrorLogger.LogMessage(Request, string.Format("Invalid CAPTCHA (response was {0})", captchaResponse), LogLevel.Warn);
                otherService.AuditLog("failed CAPTCHA", Hostname, AuditLogCategory.UserCreateFailCaptcha);
                ModelState.AddModelError("CAPTCHA", ViewRes.User.CreateStrings.CaptchaInvalid);
            }

            if (!ModelState.IsValid)
            {
                return(View(model));
            }

            if (!ipRuleManager.IsAllowed(Hostname))
            {
                ModelState.AddModelError("Restricted", restrictedErr);
                return(View(model));
            }

            var time = TimeSpan.FromTicks(DateTime.Now.Ticks - model.EntryTime);

            // Attempt to register the user
            try {
                var url  = VocaUriBuilder.CreateAbsolute(Url.Action("VerifyEmail", "User")).ToString();
                var user = Data.Create(model.UserName, model.Password, model.Email ?? string.Empty, Hostname, time, ipRuleManager.TempBannedIPs, url);
                FormsAuthentication.SetAuthCookie(user.Name, false);
                return(RedirectToAction("Index", "Home"));
            } catch (UserNameAlreadyExistsException) {
                ModelState.AddModelError("UserName", ViewRes.User.CreateStrings.UsernameTaken);
                return(View(model));
            } catch (UserEmailAlreadyExistsException) {
                ModelState.AddModelError("Email", ViewRes.User.CreateStrings.EmailTaken);
                return(View(model));
            } catch (InvalidEmailFormatException) {
                ModelState.AddModelError("Email", ViewRes.User.MySettingsStrings.InvalidEmail);
                return(View(model));
            } catch (TooFastRegistrationException) {
                ModelState.AddModelError("Restricted", restrictedErr);
                return(View(model));
            }
        }
예제 #11
0
        public string CreateEntryLink(IEntryBase entry)
        {
            if (entry.EntryType == EntryType.Tag)
            {
                var url = VocaUriBuilder.MergeUrls(baseUrl, string.Format("Tag/Details/{0}", entry.DefaultName));
                return(string.Format("<a href=\"{0}\">{1}</a>", url, entry.DefaultName));
            }

            return(CreateEntryLink(entry.EntryType, entry.Id, entry.DefaultName));
        }
예제 #12
0
        public EntryUrlParser(string hostAddress, string hostAddressSecure)
        {
            // Host addresses http and https
            var hostAddresses = VocaUriBuilder.RemoveTrailingSlash(hostAddress) + "|" + VocaUriBuilder.RemoveTrailingSlash(hostAddressSecure);

            var entryUrlRegexTemplate = @"^(?:{0}){1}/(Al|Ar|E|Es|S|L|T|Album/Details|Artist/Details|Song/Details)/(\d+)";

            entryUrlRegex = new Regex(string.Format(entryUrlRegexTemplate, hostAddresses, string.Empty), RegexOptions.IgnoreCase);

            entryUrlRegexOptionalPrefix = new Regex(string.Format(entryUrlRegexTemplate, hostAddresses, "?"), RegexOptions.IgnoreCase);
        }
예제 #13
0
        public EntryUrlParser(string hostAddress)
        {
            hostAddress = hostAddress.Replace("https://", "https?://");
            var hostAddresses = VocaUriBuilder.RemoveTrailingSlash(hostAddress);

            var entryUrlRegexTemplate = @"^(?:{0}){1}/(Al|Ar|E|Es|S|L|T|Album/Details|Artist/Details|Song/Details)/(\d+)";

            entryUrlRegex = new Regex(string.Format(entryUrlRegexTemplate, hostAddresses, string.Empty), RegexOptions.IgnoreCase);

            entryUrlRegexOptionalPrefix = new Regex(string.Format(entryUrlRegexTemplate, hostAddresses, "?"), RegexOptions.IgnoreCase);
        }
예제 #14
0
        private async Task <SyndicationItem> CreateFeedItemAsync(SongContract song, Func <SongContract, Task <string> > contentFac, Func <SongContract, string> urlFac)
        {
            var item = new SyndicationItem(song.Name, new TextSyndicationContent(await contentFac(song), TextSyndicationContentKind.Html),
                                           VocaUriBuilder.CreateAbsolute(urlFac(song)), song.Id.ToString(), song.CreateDate);

            item.Summary = new TextSyndicationContent(await contentFac(song), TextSyndicationContentKind.Html);
            if (!string.IsNullOrEmpty(song.ThumbUrl))
            {
                item.ElementExtensions.Add(new XElement(s_mediaNs + "thumbnail", new XAttribute("url", song.ThumbUrl)));
            }

            return(item);
        }
예제 #15
0
        /// <summary>
        /// Returns an URL to entry thumbnail image.
        /// Currently only used for album and artist main images.
        ///
        /// Gets the URL to the static images folder on disk if possible,
        /// otherwise gets the image from the DB.
        /// </summary>
        /// <param name="urlHelper">URL helper. Cannot be null.</param>
        /// <param name="imageInfo">Image information. Cannot be null.</param>
        /// <param name="size">Requested image size.</param>
        /// <param name="fullUrl">
        /// Whether the URL should always include the hostname and application path root.
        /// If this is false (default), the URL maybe either full (such as http://vocadb.net/Album/CoverPicture/123)
        /// or relative (such as /Album/CoverPicture/123).
        /// Usually this should be set to true if the image is to be referred from another domain.
        /// </param>
        /// <returns>URL to the image thumbnail.</returns>
        public static string ImageThumb(this UrlHelper urlHelper, IEntryImageInformation imageInfo, ImageSize size, bool fullUrl = false)
        {
            if (imageInfo == null)
            {
                return(null);
            }

            var    shouldExist = ShouldExist(imageInfo);
            string dynamicUrl  = null;

            // Use MVC dynamic actions (instead of static file) when requesting original or an image that doesn't exist on disk.
            if (imageInfo.EntryType == EntryType.Album)
            {
                if (size == ImageSize.Original)
                {
                    dynamicUrl = urlHelper.Action("CoverPicture", "Album", new { id = imageInfo.Id, v = imageInfo.Version });
                }
                else if (shouldExist && !imagePersister.HasImage(imageInfo, size))
                {
                    dynamicUrl = urlHelper.Action("CoverPictureThumb", "Album", new { id = imageInfo.Id, v = imageInfo.Version });
                }
            }
            else if (imageInfo.EntryType == EntryType.Artist)
            {
                if (size == ImageSize.Original)
                {
                    dynamicUrl = urlHelper.Action("Picture", "Artist", new { id = imageInfo.Id, v = imageInfo.Version });
                }
                else if (shouldExist && !imagePersister.HasImage(imageInfo, size))
                {
                    dynamicUrl = urlHelper.Action("PictureThumb", "Artist", new { id = imageInfo.Id, v = imageInfo.Version });
                }
            }

            var ssl = WebHelper.IsSSL(HttpContext.Current.Request);

            if (dynamicUrl != null)
            {
                return(fullUrl ? VocaUriBuilder.Absolute(dynamicUrl, ssl) : dynamicUrl);
            }

            if (!shouldExist)
            {
                var unknown = GetUnknownImageUrl(urlHelper, imageInfo);
                return(fullUrl ? VocaUriBuilder.Absolute(unknown, ssl) : unknown);
            }

            // For all other cases use the static file
            return(imagePersister.GetUrlAbsolute(imageInfo, size, ssl));
        }
예제 #16
0
        //
        // GET: /Song/Details/5

        public ActionResult Details(int id = invalidId, int albumId = 0)
        {
            if (id == invalidId)
            {
                return(NoId());
            }

            WebHelper.VerifyUserAgent(Request);

            var contract = queries.GetSongDetails(id, albumId, GetHostnameForValidHit(), null, WebHelper.GetUserLanguageCodes(Request));
            var model    = new SongDetails(contract, PermissionContext);

            var hasDescription = !model.Notes.IsEmpty;
            var prop           = PageProperties;

            prop.GlobalSearchType = EntryType.Song;
            prop.Title            = model.Name;
            prop.Description      = hasDescription ?
                                    markdownParser.GetPlainText(model.Notes.EnglishOrOriginal) :
                                    new SongDescriptionGenerator().GenerateDescription(contract.Song, Translate.SongTypeNames);
            prop.OpenGraph.ShowTwitterCard = true;

            string titleAndArtist;

            if (!string.IsNullOrEmpty(model.ArtistString))
            {
                titleAndArtist = string.Format("{0} - {1}", model.Name, model.ArtistString);
            }
            else
            {
                titleAndArtist = model.Name;
            }
            prop.PageTitle = titleAndArtist;

            prop.Subtitle = string.Format("{0} ({1})", model.ArtistString, Translate.SongTypeNames[model.SongType]);

            if (!string.IsNullOrEmpty(model.ThumbUrlMaxSize))
            {
                prop.OpenGraph.Image = model.ThumbUrlMaxSize;
            }

            prop.CanonicalUrl    = VocaUriBuilder.CreateAbsolute(Url.Action("Details", new { id })).ToString();
            prop.OpenGraph.Title = hasDescription ? string.Format("{0} ({1})", titleAndArtist, Translate.SongTypeNames[model.SongType]) : model.Name;
            prop.OpenGraph.Type  = OpenGraphTypes.Song;

            return(View(model));
        }
예제 #17
0
        private void CreateThumbnail(string oldFull, string pvId, PVForSong pv)
        {
            if (!IsImage(oldFull))
            {
                return;
            }

            var path = Path.Combine(AppConfig.StaticContentPath + "\\media-thumb\\", pvId);

            using (var stream = new FileStream(oldFull, FileMode.Open))
                using (var original = ImageHelper.OpenImage(stream)) {
                    var thumb = ImageHelper.ResizeToFixedSize(original, 560, 315);
                    thumb.Save(path);
                    pv.ThumbUrl = VocaUriBuilder.StaticResource("/media-thumb/" + pvId);
                    pv.Song.UpdateThumbUrl();
                }
        }
예제 #18
0
        public override string GetUrlAbsolute(IEntryImageInformation picture, ImageSize size, bool ssl)
        {
            ParamIs.NotNull(() => picture);

            string url;

            if (picture.Version > 0)
            {
                url = string.Format("/EntryImg/{0}/{1}?v={2}", picture.EntryType, GetFileName(picture, size), picture.Version);
            }
            else
            {
                url = string.Format("/EntryImg/{0}/{1}", picture.EntryType, GetFileName(picture, size));
            }

            return(VocaUriBuilder.Absolute(url, ssl));
        }
예제 #19
0
        private string GetUrl(string basePart, EntryType entryType, int id, string slug)
        {
            string relative;

            slug = slug ?? string.Empty;

            var slashForSlug = slug != string.Empty ? "/" : string.Empty;

            switch (entryType)
            {
            case EntryType.Album:
                relative = string.Format("Al/{0}", id);
                break;

            case EntryType.Artist:
                relative = string.Format("Ar/{0}", id);
                break;

            case EntryType.DiscussionTopic:
                relative = string.Format("discussion/topics/{0}", id);
                break;

            case EntryType.ReleaseEvent:
                relative = string.Format("E/{0}{1}{2}", id, slashForSlug, slug);
                break;

            case EntryType.ReleaseEventSeries:
                relative = string.Format("Event/SeriesDetails/{0}", id);
                break;

            case EntryType.Song:
                relative = string.Format("S/{0}", id);
                break;

            case EntryType.Tag:
                relative = string.Format("T/{0}{1}{2}", id, slashForSlug, slug);
                break;

            default:
                relative = string.Format("{0}/Details/{1}", entryType, id);
                break;
            }

            return(VocaUriBuilder.MergeUrls(basePart, relative));
        }
예제 #20
0
        public ActionResult LoginTwitterComplete(string returnUrl)
        {
            // Denied authorization
            var param = Request.QueryString["denied"];

            if (!string.IsNullOrEmpty(param))
            {
                TempData.SetStatusMessage(ViewRes.User.LoginUsingAuthStrings.SignInCancelled);
                return(View("Login", new LoginModel(string.Empty, !WebHelper.IsSSL(Request), true)));
            }

            var response = new TwitterConsumer().ProcessUserAuthorization(Hostname);

            if (response == null)
            {
                ModelState.AddModelError("Authentication", ViewRes.User.LoginUsingAuthStrings.AuthError);
                return(View("Login", new LoginModel(string.Empty, !WebHelper.IsSSL(Request), true)));
            }

            var culture = WebHelper.GetInterfaceCultureName(Request);
            var user    = Service.CheckTwitterAuthentication(response.AccessToken, Hostname, culture);

            if (user == null)
            {
                int twitterId;
                int.TryParse(response.ExtraData["user_id"], out twitterId);
                var twitterName = response.ExtraData["screen_name"];
                return(View(new RegisterOpenAuthModel(response.AccessToken, twitterName, twitterId, twitterName)));
            }

            HandleCreate(user);

            string targetUrl;

            if (!string.IsNullOrEmpty(returnUrl))
            {
                targetUrl = VocaUriBuilder.AbsoluteFromUnknown(returnUrl, preserveAbsolute: true, ssl: false);
            }
            else
            {
                targetUrl = Url.Action("Index", "Home");
            }

            return(Redirect(targetUrl));
        }
예제 #21
0
        private string GetUrl(string basePart, EntryType entryType, int id, string?slug)
        {
            slug ??= string.Empty;

            var slashForSlug = slug != string.Empty ? "/" : string.Empty;
            var relative     = entryType switch
            {
                EntryType.Album => $"Al/{id}",
                EntryType.Artist => $"Ar/{id}",
                EntryType.DiscussionTopic => $"discussion/topics/{id}",
                EntryType.ReleaseEvent => $"E/{id}{slashForSlug}{slug}",
                EntryType.ReleaseEventSeries => $"Event/SeriesDetails/{id}",
                EntryType.Song => $"S/{id}",
                EntryType.Tag => $"T/{id}{slashForSlug}{slug}",
                _ => $"{entryType}/Details/{id}",
            };

            return(VocaUriBuilder.MergeUrls(basePart, relative));
        }
예제 #22
0
        //
        // GET: /Album/Details/5

        public ActionResult Details(int id = invalidId)
        {
            if (id == invalidId)
            {
                return(NoId());
            }

            WebHelper.VerifyUserAgent(Request);

            var model = queries.GetAlbumDetails(id, WebHelper.IsValidHit(Request) ? WebHelper.GetRealHost(Request) : string.Empty);

            var prop = PageProperties;

            prop.Title                     = model.Name;
            prop.CanonicalUrl              = VocaUriBuilder.CreateAbsolute(Url.Action("Details", new { id })).ToString();
            prop.GlobalSearchType          = EntryType.Album;
            prop.OpenGraph.Image           = Url.ImageThumb(model, Model.Domain.Images.ImageSize.Original, fullUrl: true);
            prop.OpenGraph.Type            = OpenGraphTypes.Album;
            prop.OpenGraph.ShowTwitterCard = true;

            string titleAndArtist;

            if (!string.IsNullOrEmpty(model.ArtistString))
            {
                titleAndArtist = string.Format("{0} - {1}", model.Name, model.ArtistString);
            }
            else
            {
                titleAndArtist = model.Name;
            }

            PageProperties.OpenGraph.Title = string.Format("{0} ({1})", titleAndArtist, Translate.DiscTypeName(model.DiscType));

            PageProperties.PageTitle = titleAndArtist;
            PageProperties.Subtitle  = string.Format("{0} ({1})", model.ArtistString, Translate.DiscTypeName(model.DiscType));

            prop.Description = !model.Description.IsEmpty ?
                               markdownParser.GetPlainText(model.Description.EnglishOrOriginal) :
                               albumDescriptionGenerator.GenerateDescription(model, d => Translate.DiscTypeNames.GetName(d, CultureInfo.InvariantCulture));

            return(View(new AlbumDetails(model, PermissionContext)));
        }
예제 #23
0
        public ActionResult Details(int id = invalidId)
        {
            if (id == invalidId)
            {
                return(NoId());
            }

            var contract = queries.GetDetails(id);

            PageProperties.CanonicalUrl = VocaUriBuilder.CreateAbsolute(Url.Action("Details", new { id })).ToString();
            PageProperties.Description  = contract.Description;

            if (contract.FeaturedCategory == SongListFeaturedCategory.Nothing)
            {
                PageProperties.PageTitle = string.Format("{0} - {1}", ViewRes.SongList.DetailsStrings.SongList, contract.Name);
                PageProperties.Title     = contract.Name;
                PageProperties.Subtitle  = ViewRes.SongList.DetailsStrings.SongList;
            }
            else
            {
                var categoryName = Translate.SongListFeaturedCategoryNames[contract.FeaturedCategory];

                PageProperties.PageTitle = string.Format("{0} - {1}", categoryName, contract.Name);
                PageProperties.Title     = contract.Name;
                PageProperties.Subtitle  = categoryName;
            }

            var viewModel = new SongListDetailsViewModel(contract, PermissionContext);

            viewModel.SmallThumbUrl = Url.ImageThumb(contract.MainPicture, ImageSize.SmallThumb);
            var thumbUrl = viewModel.ThumbUrl = Url.ImageThumb(contract.MainPicture, ImageSize.Original) ?? Url.ImageThumb(contract.MainPicture, ImageSize.Thumb);

            if (!string.IsNullOrEmpty(thumbUrl))
            {
                PageProperties.OpenGraph.Image = thumbUrl;
            }

            PageProperties.OpenGraph.ShowTwitterCard = true;

            return(View(viewModel));
        }
예제 #24
0
        public async Task <FeedResult> Feed(IndexRouteParams indexParams)
        {
            WebHelper.VerifyUserAgent(Request);

            var pageSize    = (indexParams.pageSize.HasValue ? Math.Min(indexParams.pageSize.Value, 30) : 30);
            var sortRule    = indexParams.sort ?? SongSortRule.Name;
            var timeFilter  = DateTimeUtils.ParseFromSimpleString(indexParams.since);
            var filter      = indexParams.filter;
            var songType    = indexParams.songType ?? SongType.Unspecified;
            var matchMode   = indexParams.matchMode ?? NameMatchMode.Auto;
            var onlyWithPVs = indexParams.onlyWithPVs ?? false;
            var minScore    = indexParams.minScore ?? 0;

            var textQuery   = SearchTextQuery.Create(filter, matchMode);
            var queryParams = new SongQueryParams(textQuery,
                                                  songType != SongType.Unspecified ? new[] { songType } : new SongType[] { },
                                                  0, pageSize, false, sortRule, false, false, null)
            {
                ArtistParticipation =
                {
                    ArtistIds = !indexParams.artistId.HasValue || indexParams.artistId.Value == 0 ? null : new [] { indexParams.artistId.Value }
                },
                TimeFilter       = timeFilter,
                OnlyWithPVs      = onlyWithPVs,
                MinScore         = minScore,
                UserCollectionId = indexParams.userCollectionId ?? 0,
                FollowedByUserId = indexParams.followedByUserId ?? 0
            };

            var result = Service.FindWithThumbPreferNotNico(queryParams);

            var fac  = new SongFeedFactory();
            var feed = await fac.CreateAsync(result.Items,
                                             VocaUriBuilder.CreateAbsolute(Url.Action("Index", indexParams)),
                                             song => RenderPartialViewToStringAsync("SongItem", song),
                                             song => Url.Action("Details", new { id = song.Id }));

            return(new FeedResult(new Atom10FeedFormatter(feed)));
        }
예제 #25
0
        public ActionResult OEmbed(string url, int maxwidth = 570, int maxheight = 400, DataFormat format = DataFormat.Json, bool responsiveWrapper = false)
        {
            if (string.IsNullOrEmpty(url))
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "URL must be specified"));
            }

            var entryId = entryUrlParser.Parse(url);

            if (entryId.IsEmpty)
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "Invalid URL"));
            }

            if (entryId.EntryType != EntryType.Song)
            {
                return(HttpStatusCodeResult(HttpStatusCode.BadRequest, "Only song embeds are supported"));
            }

            var id = entryId.Id;

            var    song = songService.GetSongForApi(entryId.Id, SongOptionalFields.ThumbUrl);
            var    src  = VocaUriBuilder.CreateAbsolute(Url.Action("EmbedSong", new { songId = id })).ToString();
            string html;

            if (responsiveWrapper)
            {
                html = RenderPartialViewToString("OEmbedResponsive", new OEmbedParams {
                    Width = maxwidth, Height = maxheight, Src = src
                });
            }
            else
            {
                html = string.Format("<iframe src=\"{0}\" width=\"{1}\" height=\"{2}\"></iframe>", src, maxwidth, maxheight);
            }

            return(Object(new SongOEmbedResponse(song, maxwidth, maxheight, html), format));
        }
예제 #26
0
        public ActionResult ComposeMessage(ComposeMessage model)
        {
            if (!ModelState.IsValid)
            {
                SaveErrorsToTempData();
                return(RedirectToAction("Messages"));
            }

            var contract      = model.ToContract(LoggedUserId);
            var mySettingsUrl = VocaUriBuilder.CreateAbsolute(Url.Action("MySettings", "User")).ToString();
            var messagesUrl   = VocaUriBuilder.CreateAbsolute(Url.Action("Messages", "User")).ToString();

            try {
                Service.SendMessage(contract, mySettingsUrl, messagesUrl);
            } catch (UserNotFoundException x) {
                ModelState.AddModelError("ReceiverName", x.Message);
                SaveErrorsToTempData();
                return(RedirectToAction("Messages"));
            }

            TempData.SetStatusMessage(ViewRes.User.MessagesStrings.MessageSent);

            return(RedirectToAction("Messages"));
        }
예제 #27
0
 public static string StaticResource(this UrlHelper urlHelper, string url)
 {
     return(VocaUriBuilder.StaticResource(url));
 }
예제 #28
0
        public void RequestEmailVerification()
        {
            var url = VocaUriBuilder.CreateAbsolute(Url.Action("VerifyEmail", "User"));

            Data.RequestEmailVerification(LoggedUserId, url.ToString());
        }
예제 #29
0
 public override string GetUrlById(string id)
 {
     return(VocaUriBuilder.StaticResource("/media/" + id));
 }
예제 #30
0
 protected ControllerBase()
 {
     PageProperties.OpenGraph.Image = VocaUriBuilder.StaticResource("/img/vocaDB-title-large.png");
 }