Merge pull request #3 from tidusjar/develop

Bringing my Develop up to date with source
pull/2148/head
Anojh Thayaparan 7 years ago committed by GitHub
commit bf47d4e940
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
# Changelog
## (unreleased)
## v3.0.3111 (2018-03-27)
### **New Features**
@ -26,6 +26,8 @@
- Added the ability to refresh out backend metadata (#2078) [Jamie]
- Update README.md. [zobe123]
### **Fixes**
- Specific favicons for different platforms. [louis-lau]

@ -11,8 +11,12 @@ ____
___
We also now have merch up on Teespring!
[![Report a bug](http://i.imgur.com/xSpw482.png)](https://forums.ombi.io/viewforum.php?f=10) [![Feature request](http://i.imgur.com/mFO0OuX.png)](https://forums.ombi.io/posting.php?mode=post&f=20)
[EU Store](https://teespring.com/stores/ombi-eu)
[US Store](https://teespring.com/stores/ombi-us)
___
| Service | Stable | Develop |
@ -56,7 +60,7 @@ Supported notifications:
### The difference between Version 3 and 2
Over the last 8 months, we focused on the main functions on Ombi, a complete rewrite while making it better, faster and more stable.
Over the last year, we focused on the main functions on Ombi, a complete rewrite while making it better, faster and more stable.
We have already done most of the work, but some features are still be missing in this first version.
We are planning to bring back these features in V3 but for now you can find a list below with a quick comparison of features between v2 and v3.
@ -70,13 +74,13 @@ We are planning to bring back these features in V3 but for now you can find a li
| Landing page | Yes (brand new) | Yes |
| Login page | Yes (brand new) | Yes |
| Custom Notification Messages | Yes | No |
| Sending newsletters | Planned | Yes |
| Sending newsletters | Yes | Yes |
| Send a Mass Email | Yes | Yes |
| SickRage | Yes | Yes |
| CouchPotato | Yes | Yes |
| DogNzb | Yes | No |
| Issues | Yes | Yes |
| Headphones | No (support dropped) | Yes |
| Headphones | No | Yes |
# Feature Requests
Feature requests are handled on FeatHub.

@ -77,13 +77,19 @@ namespace Ombi.Api.Emby
request.AddJsonBody(body);
request.AddHeader("Accept", "application/json");
request.AddContentHeader("Content-Type", "application/json");
AddEmbyHeaders(request);
var obj = await Api.Request<EmbyConnectUser>(request);
return obj;
}
private static void AddEmbyHeaders(Request request)
{
request.AddHeader("Accept", "application/json");
request.AddHeader("X-Application", $"Ombi/{AssemblyHelper.GetRuntimeVersion()}");
request.AddContentHeader("Content-Type", "application/json");
}
public async Task<EmbyItemContainer<MovieInformation>> GetCollection(string mediaId, string apiKey, string userId, string baseUrl)
{
var request = new Request($"emby/users/{userId}/items?parentId={mediaId}", baseUrl, HttpMethod.Get);

@ -29,11 +29,19 @@ namespace Ombi.Notifications
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
RequestedUser = req?.RequestedUser?.UserName;
UserName = req?.RequestedUser?.UserName;
if (UserName.IsNullOrEmpty())
{
// Can be set if it's an issue
UserName = req?.RequestedUser?.UserName;
}
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
Title = title;
RequestedDate = req?.RequestedDate.ToString("D");
Type = req?.RequestType.ToString();
if (Type.IsNullOrEmpty())
{
Type = req?.RequestType.ToString();
}
Overview = req?.Overview;
Year = req?.ReleaseDate.Year.ToString();
PosterImage = req?.RequestType == RequestType.Movie ?
@ -65,11 +73,19 @@ namespace Ombi.Notifications
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
RequestedUser = req?.RequestedUser?.UserName;
UserName = req?.RequestedUser?.UserName;
if (UserName.IsNullOrEmpty())
{
// Can be set if it's an issue
UserName = req?.RequestedUser?.UserName;
}
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
Title = title;
RequestedDate = req?.RequestedDate.ToString("D");
Type = req?.RequestType.ToString();
if (Type.IsNullOrEmpty())
{
Type = req?.RequestType.ToString();
}
Overview = req?.ParentRequest.Overview;
Year = req?.ParentRequest.ReleaseDate.Year.ToString();
PosterImage = req?.RequestType == RequestType.Movie ?
@ -128,6 +144,7 @@ namespace Ombi.Notifications
IssueSubject = opts.Substitutes.TryGetValue("IssueSubject", out val) ? val : string.Empty;
NewIssueComment = opts.Substitutes.TryGetValue("NewIssueComment", out val) ? val : string.Empty;
UserName = opts.Substitutes.TryGetValue("IssueUser", out val) ? val : string.Empty;
Type = opts.Substitutes.TryGetValue("RequestType", out val) ? val : string.Empty;
}
// User Defined

@ -111,7 +111,7 @@ namespace Ombi.Schedule.Jobs.Ombi
}
}
if (!test)
{
// Get the users to send it to
@ -259,19 +259,11 @@ namespace Ombi.Schedule.Jobs.Ombi
var ordered = plexContentToSend.OrderByDescending(x => x.AddedAt);
foreach (var content in ordered)
{
if (content.TheMovieDbId.IsNullOrEmpty())
int.TryParse(content.TheMovieDbId, out var movieDbId);
if (movieDbId <= 0)
{
// Maybe we should try the ImdbId?
if (content.ImdbId.HasValue())
{
var findResult = await _movieApi.Find(content.ImdbId, ExternalSource.imdb_id);
var movieId = findResult.movie_results?[0]?.id ?? 0;
content.TheMovieDbId = movieId.ToString();
}
continue;
}
int.TryParse(content.TheMovieDbId, out var movieDbId);
var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId);
if (info == null)
{

@ -46,8 +46,7 @@ namespace Ombi.Schedule.Processor
if (masterBranch)
{
latestRelease = doc.DocumentNode.Descendants("h2")
.FirstOrDefault(x => x.InnerText == "(unreleased)");
// TODO: Change this to InnterText != "(unreleased)" once we go live and it's not a prerelease
.FirstOrDefault(x => x.InnerText != "(unreleased)");
}
else
{

@ -58,10 +58,11 @@ const routes: Routes = [
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLocation) {
const base = platformLocation.getBaseHrefFromDOM();
const version = Math.floor(Math.random() * 999999999);
if (base.length > 1) {
return new TranslateHttpLoader(http, `${base}/translations/`, ".json");
return new TranslateHttpLoader(http, `${base}/translations/`, `.json?v=${version}`);
}
return new TranslateHttpLoader(http, "/translations/", ".json");
return new TranslateHttpLoader(http, "/translations/", `.json?v=${version}`);
}
@NgModule({

@ -1,79 +1,80 @@
<div *ngIf="issue">
<div class="myBg backdrop" [style.background-image]="backgroundPath"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<h1>{{issue.title}} </h1>
<div class="col-md-6">
<img class="img-responsive poster" src="{{posterPath}}" alt="poster">
<span class="label label-info">{{IssueStatus[issue.status]}}</span>
<span class="label label-success">{{issue.issueCategory.value}}</span>
<div class="row">
<div class="myBg backdrop" [style.background-image]="backgroundPath"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<h1>{{issue.title}} </h1>
<div class="col-md-6">
<img class="img-responsive poster" src="{{posterPath}}" alt="poster">
<span class="label label-info">{{IssueStatus[issue.status]}}</span>
<span class="label label-success">{{issue.issueCategory.value}}</span>
<h3 *ngIf="issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.alias}}</h3>
<h3 *ngIf="!issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.userName}}</h3>
<h3 *ngIf="issue.subject">{{'Issues.Subject' | translate}}: {{issue.subject}}</h3>
<br>
<div class="form-group">
<label for="description" class="control-label" [translate]="'Issues.Description'"></label>
<div>
<textarea class="form-control-custom form-control" disabled="disabled" [(ngModel)]="issue.description" rows="5" type="text"></textarea>
<h3 *ngIf="issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.alias}}</h3>
<h3 *ngIf="!issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.userName}}</h3>
<h3 *ngIf="issue.subject">{{'Issues.Subject' | translate}}: {{issue.subject}}</h3>
<br>
<div class="form-group">
<label for="description" class="control-label" [translate]="'Issues.Description'"></label>
<div>
<textarea class="form-control-custom form-control" disabled="disabled" [(ngModel)]="issue.description" rows="5" type="text"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="row chat-window col-xs-7 col-md-5" id="chat_window_1" style="margin-left:10px;">
<div class="col-xs-12 col-md-12">
<div class="panel panel-default">
<div class="panel-heading top-bar">
<div class="col-md-8 col-xs-8">
<h3 class="panel-title">
<span class="glyphicon glyphicon-comment"></span> {{'Issues.Comments' | translate}}
</h3>
<div class="row chat-window col-xs-7 col-md-5" id="chat_window_1" style="margin-left:10px;">
<div class="col-xs-12 col-md-12">
<div class="panel panel-default">
<div class="panel-heading top-bar">
<div class="col-md-8 col-xs-8">
<h3 class="panel-title">
<span class="glyphicon glyphicon-comment"></span> {{'Issues.Comments' | translate}}
</h3>
</div>
</div>
</div>
<div *ngIf="comments" class="panel-body msg_container_base">
<div *ngIf="comments.length <= 0" class="row msg_container base_receive">
<div class="col-md-10 col-xs-10">
<div class="messages msg_sent">
<p [translate]="'Issues.NoComments'"></p>
<div *ngIf="comments" class="panel-body msg_container_base">
<div *ngIf="comments.length <= 0" class="row msg_container base_receive">
<div class="col-md-10 col-xs-10">
<div class="messages msg_sent">
<p [translate]="'Issues.NoComments'"></p>
</div>
</div>
</div>
</div>
<div *ngFor="let comment of comments" class="row msg_container" [ngClass]="{'base_sent': comment.adminComment, 'base_receive': !comment.adminComment}">
<div class="col-md-10 col-xs-10">
<div class="messages msg_sent">
<p>{{comment.comment}}</p>
<time>{{comment.username}} • {{comment.date | date:'short'}}</time>
<div *ngFor="let comment of comments" class="row msg_container" [ngClass]="{'base_sent': comment.adminComment, 'base_receive': !comment.adminComment}">
<div class="col-md-10 col-xs-10">
<div class="messages msg_sent">
<p>{{comment.comment}}</p>
<time>{{comment.username}} • {{comment.date | date:'short'}}</time>
</div>
</div>
</div>
</div>
</div>
<div class="panel-footer">
<div class="input-group">
<input id="btn-input" type="text" class="form-control input-sm chat_input" [(ngModel)]="newComment.comment" [attr.placeholder]="'Issues.WriteMessagePlaceholder' | translate" />
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" (click)="addComment()" [translate]="'Issues.SendMessageButton'"></button>
</span>
</div>
<div class="panel-footer">
<div class="input-group">
<input id="btn-input" type="text" class="form-control input-sm chat_input" [(ngModel)]="newComment.comment" [attr.placeholder]="'Issues.WriteMessagePlaceholder' | translate" />
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" (click)="addComment()" [translate]="'Issues.SendMessageButton'"></button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<div *ngIf="isAdmin && settings">
<div *ngIf="issue.status === IssueStatus.Pending && settings.enableInProgress">
<button class="btn btn-primary btn-sm" (click)="inProgress()" [translate]="'Issues.MarkInProgress'"></button>
</div>
<div *ngIf="issue.status === IssueStatus.Pending && !settings.enableInProgress || issue.status == IssueStatus.InProgress">
<button class="btn btn-primary btn-sm" (click)="resolve()" [translate]="'Issues.MarkResolved'"></button>
<div class="col-md-12">
<div *ngIf="isAdmin && settings">
<div *ngIf="issue.status === IssueStatus.Pending && settings.enableInProgress">
<button class="btn btn-primary btn-sm bottom-btn" (click)="inProgress()" [translate]="'Issues.MarkInProgress'"></button>
</div>
<div *ngIf="issue.status === IssueStatus.Pending && !settings.enableInProgress || issue.status == IssueStatus.InProgress">
<button class="btn btn-primary btn-sm bottom-btn" (click)="resolve()" [translate]="'Issues.MarkResolved'"></button>
</div>
</div>
</div>
</div>
</div>

@ -70,8 +70,9 @@ body{
.tint {
z-index: -1;
}
img-responsive poster {
display:block;
.img-responsive.poster {
margin-bottom: 21px;
width: 50%;
}
img {
display: block;
@ -143,4 +144,8 @@ img {
border-top: 1px solid transparent;
border-bottom-right-radius: -1;
border-bottom-left-radius: -1;
}
.bottom-btn{
margin-bottom: 10px;
}

@ -14,32 +14,32 @@
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
<li>
<a (click)="setOrder('requestedDate')">{{ 'Requests.SortRequestDate' | translate }}
<a class="active" (click)="setOrder('requestedDate', $event)">{{ 'Requests.SortRequestDate' | translate }}
<span *ngIf="order === 'requestedDate'">
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
</span>
</a>
<a (click)="setOrder('title')">{{ 'Requests.SortTitle' | translate}}
<a (click)="setOrder('title', $event)">{{ 'Requests.SortTitle' | translate}}
<span *ngIf="order === 'title'">
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
</span>
</a>
<a (click)="setOrder('releaseDate')">{{ 'Requests.TheatricalReleaseSort' | translate }}
<a (click)="setOrder('releaseDate', $event)">{{ 'Requests.TheatricalReleaseSort' | translate }}
<span *ngIf="order === 'releaseDate'">
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
</span>
</a>
<a (click)="setOrder('requestedUser.userAlias')">{{ 'Requests.SortRequestedBy' | translate }}
<a (click)="setOrder('requestedUser.userAlias', $event)">{{ 'Requests.SortRequestedBy' | translate }}
<span *ngIf="order === 'requestedUser.userAlias'">
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
</span>
</a>
<a (click)="setOrder('status')">{{ 'Requests.SortStatus' | translate }}
<a (click)="setOrder('status', $event)">{{ 'Requests.SortStatus' | translate }}
<span *ngIf="order === 'status'">
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
@ -78,40 +78,42 @@
</a>
</div>
<br />
<div>
<span>{{ 'Requests.RequestedBy' | translate }} </span>
<span *ngIf="!isAdmin">{{request.requestedUser.userName}}</span>
<span *ngIf="isAdmin && request.requestedUser.alias">{{request.requestedUser.alias}}</span>
<span *ngIf="isAdmin && !request.requestedUser.alias">{{request.requestedUser.userName}}</span>
</div>
<div>
<span>{{ 'Requests.Status' | translate }} </span>
<span class="label label-success" id="requestedStatusLabel">{{request.status}}</span>
</div>
<div class="request-info">
<div class="request-by">
<span>{{ 'Requests.RequestedBy' | translate }} </span>
<span *ngIf="!isAdmin">{{request.requestedUser.userName}}</span>
<span *ngIf="isAdmin && request.requestedUser.alias">{{request.requestedUser.alias}}</span>
<span *ngIf="isAdmin && !request.requestedUser.alias">{{request.requestedUser.userName}}</span>
</div>
<div class="request-status">
<span>{{ 'Requests.Status' | translate }} </span>
<span class="label label-success" id="requestedStatusLabel">{{request.status}}</span>
</div>
<div>
<span>{{ 'Requests.RequestStatus' | translate }} </span>
<span *ngIf="request.available" class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span>
<span *ngIf="request.approved && !request.available" id="processingRequestLabel" class="label label-info" [translate]="'Common.ProcessingRequest'"></span>
<span *ngIf="request.denied" class="label label-danger" id="requestDeclinedLabel" [translate]="'Common.RequestDenied'"></span>
<span *ngIf="request.deniedReason" title="{{request.deniedReason}}">
<i class="fa fa-info-circle"></i>
</span>
<span *ngIf="!request.approved && !request.availble && !request.denied" id="pendingApprovalLabel" class="label label-warning"
[translate]="'Common.PendingApproval'"></span>
<div class="requested-status">
<span>{{ 'Requests.RequestStatus' | translate }} </span>
<span *ngIf="request.available" class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span>
<span *ngIf="request.approved && !request.available" id="processingRequestLabel" class="label label-info" [translate]="'Common.ProcessingRequest'"></span>
<span *ngIf="request.denied" class="label label-danger" id="requestDeclinedLabel" [translate]="'Common.RequestDenied'"></span>
<span *ngIf="request.deniedReason" title="{{request.deniedReason}}">
<i class="fa fa-info-circle"></i>
</span>
<span *ngIf="!request.approved && !request.availble && !request.denied" id="pendingApprovalLabel" class="label label-warning"
[translate]="'Common.PendingApproval'"></span>
</div>
<div *ngIf="request.denied" id="requestDenied">
{{ 'Requests.Denied' | translate }}
<i style="color:red;" class="fa fa-check"></i>
</div>
<div *ngIf="request.denied" id="requestDenied">
{{ 'Requests.Denied' | translate }}
<i style="color:red;" class="fa fa-check"></i>
</div>
</div>
<div id="releaseDate">{{ 'Requests.TheatricalRelease' | translate: {date: request.releaseDate | date: 'mediumDate'} }}</div>
<div *ngIf="request.digitalReleaseDate" id="digitalReleaseDate">{{ 'Requests.DigitalRelease' | translate: {date: request.digitalReleaseDate | date: 'mediumDate'} }}</div>
<div id="requestedDate">{{ 'Requests.RequestDate' | translate }} {{request.requestedDate | date}}</div>
<br />
<div id="releaseDate">{{ 'Requests.TheatricalRelease' | translate: {date: request.releaseDate | date: 'mediumDate'} }}</div>
<div *ngIf="request.digitalReleaseDate" id="digitalReleaseDate">{{ 'Requests.DigitalRelease' | translate: {date: request.digitalReleaseDate | date: 'mediumDate'} }}</div>
<div id="requestedDate">{{ 'Requests.RequestDate' | translate }} {{request.requestedDate | date}}</div>
<br />
</div>
<div *ngIf="isAdmin">
<div *ngIf="request.qualityOverrideTitle">{{ 'Requests.QualityOverride' | translate }}
<span>{{request.qualityOverrideTitle}} </span>
@ -127,13 +129,15 @@
<div *ngIf="!request.approved" id="approveBtn">
<form>
<button (click)="approve(request)" style="text-align: right" class="btn btn-sm btn-success-outline approve" type="submit">
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}</button>
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
</form>
<!--Radarr Root Folder-->
<div *ngIf="radarrRootFolders" class="btn-group btn-split" id="rootFolderBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}</button>
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
@ -148,7 +152,8 @@
<!--Radarr Quality Profiles -->
<div *ngIf="radarrProfiles" class="btn-group btn-split" id="changeQualityBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}</button>
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
@ -162,19 +167,23 @@
<div *ngIf="!request.denied" id="denyBtn">
<button type="button" (click)="deny(request)" class="btn btn-sm btn-danger-outline deny">
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}</button>
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}
</button>
</div>
</div>
<form id="removeBtn">
<button (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete">
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}</button>
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}
</button>
</form>
<form id="markBtnGroup">
<button id="unavailableBtn" *ngIf="request.available" (click)="changeAvailability(request, false)" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change">
<i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}</button>
<i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
</button>
<button id="availableBtn" *ngIf="!request.available" (click)="changeAvailability(request, true)" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change">
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}</button>
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
</form>
@ -183,7 +192,7 @@
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issuesBtn">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
aria-expanded="true">
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>

@ -175,11 +175,18 @@ export class MovieRequestsComponent implements OnInit {
});
}
public setOrder(value: string) {
public setOrder(value: string, el: any) {
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
const parent = el.parentElement;
const previousFilter = parent.querySelector(".active");
if (this.order === value) {
this.reverse = !this.reverse;
this.reverse = !this.reverse;
} else {
previousFilter.className = "";
el.className = "active";
}
this.order = value;
}

@ -66,7 +66,19 @@ export class TvRequestsComponent implements OnInit {
public openClosestTab(el: any) {
const rowclass = "undefined ng-star-inserted";
el = el.toElement || el.relatedTarget || el.target;
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
if (el.nodeName === "BUTTON") {
const isButtonAlreadyActive = el.parentElement.querySelector(".active");
// if a Button already has Class: .active
if (isButtonAlreadyActive) {
isButtonAlreadyActive.classList.remove("active");
} else {
el.className += " active";
}
}
while (el.className !== rowclass) {
// Increment the loop to the parent node until we find the row we need
el = el.parentNode;

@ -38,7 +38,7 @@
<span>Discord</span>
</td>
<td>
<a href="https://discord.gg/KxYZ64w" target="_blank">https://discord.gg/KxYZ64w</a>
<a href="https://discord.gg/Sa7wNWb" target="_blank">https://discord.gg/</a>
</td>
</tr>
@ -50,6 +50,22 @@
<a href="https://www.reddit.com/r/Ombi/" target="_blank">https://www.reddit.com/r/Ombi/</a>
</td>
</tr>
<tr>
<td>
<span>Issues</span>
</td>
<td>
<a href="https://github.com/tidusjar/Ombi/issues" target="_blank">https://github.com/tidusjar/Ombi/issues</a>
</td>
</tr>
<tr>
<td>
<span>Wiki</span>
</td>
<td>
<a href="https://github.com/tidusjar/Ombi/wiki" target="_blank">https://github.com/tidusjar/Ombi/wiki</a>
</td>
</tr>
<tr>
<td>
<span>OS Architecture</span>

@ -28,8 +28,8 @@ export class JobsComponent implements OnInit {
embyContentSync: [x.embyContentSync, Validators.required],
plexContentSync: [x.plexContentSync, Validators.required],
userImporter: [x.userImporter, Validators.required],
sonarrSync: [x.radarrSync, Validators.required],
radarrSync: [x.sonarrSync, Validators.required],
sonarrSync: [x.sonarrSync, Validators.required],
radarrSync: [x.radarrSync, Validators.required],
sickRageSync: [x.sickRageSync, Validators.required],
refreshMetadata: [x.refreshMetadata, Validators.required],
newsletter: [x.newsletter, Validators.required],

@ -1,68 +1,70 @@
<div *ngIf="user">
<h3>User: {{user.userName}}</h3>
<button type="button" class="btn btn-primary-outline" style="float:right;" [routerLink]="['/usermanagement/']">Back</button>
<div class="user-details">
<h3>User: {{user.userName}}</h3>
<button type="button" class="btn btn-primary-outline" style="float:right;" [routerLink]="['/usermanagement/']">Back</button>
<p-confirmDialog></p-confirmDialog>
<div class="modal-body" style="margin-top: 45px;">
<div class="col-md-6">
<h4>User Details</h4>
</div>
<div class="col-md-6">
<h4>Roles</h4>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="username" class="control-label">Username</label>
<div>
<input type="text" [(ngModel)]="user.userName" [readonly]="true" class="form-control form-control-custom " id="username" name="username" value="{{user?.userName}}">
</div>
<p-confirmDialog></p-confirmDialog>
<div class="modal-body" style="margin-top: 45px;">
<div class="col-md-6">
<h4>User Details</h4>
</div>
<div class="form-group">
<label for="alias" class="control-label">Alias</label>
<div>
<input type="text" [(ngModel)]="user.alias" class="form-control form-control-custom " id="alias" name="alias" value="{{user?.alias}}">
</div>
<div class="col-md-6">
<h4>Roles</h4>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="username" class="control-label">Username</label>
<div>
<input type="text" [(ngModel)]="user.userName" [readonly]="true" class="form-control form-control-custom " id="username" name="username" value="{{user?.userName}}">
</div>
</div>
<div class="form-group">
<label for="alias" class="control-label">Alias</label>
<div>
<input type="text" [(ngModel)]="user.alias" class="form-control form-control-custom " id="alias" name="alias" value="{{user?.alias}}">
</div>
</div>
<div class="form-group">
<label for="emailAddress" class="control-label">Email Address</label>
<div>
<input type="text" [(ngModel)]="user.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{user?.emailAddress}}" [disabled]="user?.userType == 2">
<div class="form-group">
<label for="emailAddress" class="control-label">Email Address</label>
<div>
<input type="text" [(ngModel)]="user.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{user?.emailAddress}}" [disabled]="user?.userType == 2">
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div *ngFor="let c of user.claims">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" [(ngModel)]="c.enabled" [value]="c.value" id="create{{c.value}}" [attr.name]="'create' + c.value" ng-checked="c.enabled">
<label for="create{{c.value}}">{{c.value | humanize}}</label>
<div class="col-md-6">
<div *ngFor="let c of user.claims">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" [(ngModel)]="c.enabled" [value]="c.value" id="create{{c.value}}" [attr.name]="'create' + c.value" ng-checked="c.enabled">
<label for="create{{c.value}}">{{c.value | humanize}}</label>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="movieRequestLimit" class="control-label">Movie Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.movieRequestLimit" class="form-control form-small form-control-custom " id="movieRequestLimit" name="movieRequestLimit" value="{{user?.movieRequestLimit}}">
<div class="form-group">
<label for="movieRequestLimit" class="control-label">Movie Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.movieRequestLimit" class="form-control form-small form-control-custom " id="movieRequestLimit" name="movieRequestLimit" value="{{user?.movieRequestLimit}}">
</div>
</div>
</div>
<div class="form-group">
<label for="episodeRequestLimit" class="control-label">Episode Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.episodeRequestLimit" class="form-control form-small form-control-custom " id="episodeRequestLimit" name="episodeRequestLimit" value="{{user?.episodeRequestLimit}}">
<div class="form-group">
<label for="episodeRequestLimit" class="control-label">Episode Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.episodeRequestLimit" class="form-control form-small form-control-custom " id="episodeRequestLimit" name="episodeRequestLimit" value="{{user?.episodeRequestLimit}}">
</div>
</div>
</div>
</div>
</div>
<div>
<button type="button" class="btn btn-primary-outline" (click)="update()">Update</button>
<button type="button" class="btn btn-danger-outline" (click)="delete()">Delete</button>
<button type="button" style="float:right;" class="btn btn-info-outline" (click)="resetPassword()" pTooltip="You need your SMTP settings setup">Send Reset Password Link</button>
<div>
<button type="button" class="btn btn-primary-outline" (click)="update()">Update</button>
<button type="button" class="btn btn-danger-outline" (click)="delete()">Delete</button>
<button type="button" style="float:right;" class="btn btn-info-outline" (click)="resetPassword()" pTooltip="You need your SMTP settings setup">Send Reset Password Link</button>
</div>
</div>
</div>

@ -16,7 +16,7 @@
</td>
</a>
</th>
<th (click)="setOrder('userName')">
<th class="active" (click)="setOrder('userName', $event)">
<a>
Username
</a>
@ -24,7 +24,7 @@
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
</span>
</th>
<th (click)="setOrder('alias')">
<th (click)="setOrder('alias', $event)">
<a>
Alias
</a>
@ -32,7 +32,7 @@
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
</span>
</th>
<th (click)="setOrder('emailAddress')">
<th (click)="setOrder('emailAddress', $event)">
<a>
Email
</a>
@ -44,13 +44,13 @@
<th>
Roles
</th>
<th (click)="setOrder('lastLoggedIn')">
<th (click)="setOrder('lastLoggedIn', $event)">
<a> Last Logged In</a>
<span *ngIf="order === 'lastLoggedIn'">
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
</span>
</th>
<th (click)="setOrder('userType')">
<th (click)="setOrder('userType', $event)">
<a>
User Type
</a>

@ -93,9 +93,21 @@ export class UserManagementComponent implements OnInit {
this.bulkEpisodeLimit = undefined;
}
public setOrder(value: string) {
public setOrder(value: string, el: any) {
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
if (el.nodeName === "A") {
el = el.parentElement;
}
const parent = el.parentElement;
const previousFilter = parent.querySelector(".active");
if (this.order === value) {
this.reverse = !this.reverse;
this.reverse = !this.reverse;
} else {
previousFilter.className = "";
el.className = "active";
}
this.order = value;

@ -126,6 +126,7 @@ legend {
box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.2);
}*/
.navbar-default {
background-color: #0a0a0a;
border-color: #0a0a0a;
@ -348,4 +349,7 @@ button.list-group-item:focus {
width: 100%;
height: 100%;
position: absolute;
}
}
table.table > thead > tr > th.active {
background-color: transparent;
}

@ -10,6 +10,8 @@ $danger-colour: #d9534f;
$success-colour: #5cb85c;
$i: !important;
@media (min-width: 768px ) {
.bottom-align-text {
position: absolute;
@ -131,6 +133,10 @@ h1 {
font-size: 1.9rem $i;
}
a.active {
background-color: $primary-colour;
}
p {
font-size: 1.1rem $i;
}
@ -947,4 +953,5 @@ a > h4:hover {
.searchWidth {
width: 94%;
}
}

@ -283,6 +283,7 @@ namespace Ombi.Controllers
notificationModel.Substitutes.Add("IssueStatus", issue.Status.ToString());
notificationModel.Substitutes.Add("IssueSubject", issue.Subject);
notificationModel.Substitutes.Add("IssueUser", issueReportedUsername);
notificationModel.Substitutes.Add("RequestType", notificationModel.RequestType.ToString());
}
}
}

@ -67,11 +67,27 @@ namespace Ombi
}
}
DeleteSchedulesDb();
Console.WriteLine($"We are running on {urlValue}");
BuildWebHost(args).Run();
}
private static void DeleteSchedulesDb()
{
try
{
if (File.Exists("Schedules.db"))
{
File.Delete("Schedules.db");
}
}
catch (Exception)
{
}
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
@ -98,9 +114,9 @@ namespace Ombi
" Use \"*\" to indicate that the server should listen for requests on any IP address or hostname using the specified port and protocol (for example, http://*:5000). " +
"The protocol (http:// or https://) must be included with each URL. Supported formats vary between servers.", Default = "http://*:5000")]
public string Host { get; set; }
[Option("storage", Required = false, HelpText = "Storage path, where we save the logs and database")]
public string StoragePath { get; set; }
}
}

@ -44,7 +44,7 @@ namespace Ombi
Console.WriteLine(env.ContentRootPath);
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", false, true)
.AddJsonFile("appsettings.json", false, false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
.AddEnvironmentVariables();
Configuration = builder.Build();

@ -63,12 +63,13 @@ O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i
<meta name="description" content="Ombi, media request tool">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>@appName</title>
<meta property="og:title" content=“@appName”/>
<meta property="og:image" content="~/images/logo.png"/>
<meta property="og:site_name" content=“@appName”/>
<base href="/@baseUrl"/>
<link rel="apple-touch-icon" sizes="180x180" href="~/images/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="~/images/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="~/images/favicon/favicon-16x16.png">
<link rel="manifest" href="~/images/favicon/site.webmanifest">
<link rel="mask-icon" href="~/images/favicon/safari-pinned-tab.svg" color="#df691a">
<link rel="shortcut icon" href="~/images/favicon/favicon.ico">
<meta name="msapplication-TileColor" content="#df691a">

@ -1,21 +0,0 @@
SERVICE="Ombi"
# change directory to location of project.json
pushd ./
# run dotnet publish, specify release build
dotnet publish -c Release
# equivalent to cd .. (go back to previous directory)
#popd
# Create a docker image tagged with the name of the project:latest
docker build -t "$SERVICE":latest .
# Check to see if this container exists.
CONTAINER=`docker ps --all | grep "$SERVICE"`
# if it doesn't, then just run this.
if [ -z "$CONTAINER" ]; then
docker run -i -p 8000:5000 --name $SERVICE -t $SERVICE:latest
# if it does exist; nuke it and then run the new one
else
docker rm $SERVICE
docker run -i -p 8000:5000 --name $SERVICE -t $SERVICE:latest
fi
read -p "Press enter to continue"

File diff suppressed because it is too large Load Diff

@ -21,11 +21,7 @@
"Request": "Anmod",
"Denied": "Afvist",
"Approve": "Godkendt",
<<<<<<< HEAD
"PartlyAvailable": "Delvist tilgængelig",
=======
"PartlyAvailable": "Partly Available",
>>>>>>> New translations en.json (Danish)
"Errors": {
"Validation": "Tjek venligst dine indtastede værdier"
}
@ -91,7 +87,6 @@
"Trailer": "Trailer"
},
"TvShows": {
<<<<<<< HEAD
"Popular": "Populære",
"Trending": "Aktuelle",
"MostWatched": "Mest sete",
@ -105,18 +100,6 @@
"SubmitRequest": "Send anmodning",
"Season": "Sæson: {{seasonNumber}}",
"SelectAllInSeason": "Vælg alle i sæson {{seasonNumber}}"
=======
"Popular": "Popular",
"Trending": "Trending",
"MostWatched": "Most Watched",
"MostAnticipated": "Most Anticipated",
"Results": "Results",
"AirDate": "Air Date:",
"AllSeasons": "All Seasons",
"FirstSeason": "First Season",
"LatestSeason": "Latest Season",
"Select": "Select ..."
>>>>>>> New translations en.json (Danish)
}
},
"Requests": {

Loading…
Cancel
Save