Merge remote-tracking branch 'origin/release/10.2' into dev

pull/7860/head
Oliver Günther 5 years ago
commit 3d0e3cb3d7
No known key found for this signature in database
GPG Key ID: A3A8BDAD7C0C552C
  1. 11
      app/controllers/application_controller.rb
  2. 2
      frontend/src/app/ckeditor/ckeditor-augmented-textarea.component.ts
  3. 2
      frontend/src/app/modules/common/ckeditor/op-ckeditor.component.ts
  4. 4
      frontend/src/app/modules/common/config/configuration.service.ts
  5. 12
      frontend/src/app/modules/hal/resources/error-resource.ts
  6. 12
      frontend/src/app/modules/hal/resources/hal-resource.ts
  7. 2
      frontend/src/app/modules/hal/services/hal-aware-error-handler.ts
  8. 6
      frontend/src/app/modules/hal/services/hal-resource.service.ts
  9. 14
      frontend/src/app/sentry/sentry-reporter.ts
  10. 2
      lib/open_project/version.rb
  11. 2
      modules/meeting/app/controllers/meeting_contents_controller.rb
  12. 7
      modules/meeting/app/views/meeting_contents/_show.html.erb
  13. 8
      modules/meeting/app/views/meeting_contents/show.html.erb

@ -272,11 +272,14 @@ class ApplicationController < ActionController::Base
def require_login
unless User.current.logged?
# Ensure we reset the session to terminate any old session objects
reset_session
respond_to do |format|
format.any(:html, :atom) { redirect_to main_app.signin_path(back_url: login_back_url) }
format.any(:html, :atom) do
# Ensure we reset the session to terminate any old session objects
# but ONLY for html requests to avoid double-resetting sessions
reset_session
redirect_to main_app.signin_path(back_url: login_back_url)
end
auth_header = OpenProject::Authentication::WWWAuthenticate.response_header(request_headers: request.headers)

@ -127,7 +127,7 @@ export class CkeditorAugmentedTextareaComponent implements OnInit, OnDestroy {
this.wrappedTextArea.val(this.ckEditorInstance.getRawData());
} catch (e) {
console.error(`Failed to save CKEditor body to textarea: ${e}.`);
this.Notifications.addError(e || this.I18n.t('js.errors.internal'));
this.Notifications.addError(e || this.I18n.t('js.error.internal'));
// Avoid submission of the form
return false;

@ -126,7 +126,7 @@ export class OpCkeditorComponent implements OnInit, OnDestroy {
console.error(`Failed to save CKEditor content: ${e}.`);
let error = this.I18n.t(
'js.editor.error_saving_failed',
{error: e || this.I18n.t('js.errors.internal')}
{error: e || this.I18n.t('js.error.internal')}
);
if (notificationOnError) {

@ -113,10 +113,10 @@ export class ConfigurationService {
}
private userPreference(pref:string) {
return this.configuration.userPreferences[pref];
return _.get(this.configuration, ['userPreferences', pref]);
}
private systemPreference(pref:string) {
return this.configuration[pref];
return _.get(this.configuration, pref);
}
}

@ -28,6 +28,7 @@
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
import {FormResource} from 'core-app/modules/hal/resources/form-resource';
import {HttpErrorResponse} from "@angular/common/http";
export const v3ErrorIdentifierQueryInvalid = 'urn:openproject-org:api:v3:errors:InvalidQuery';
export const v3ErrorIdentifierMultipleErrors = 'urn:openproject-org:api:v3:errors:MultipleErrors';
@ -38,8 +39,19 @@ export class ErrorResource extends HalResource {
public details:any;
public errorIdentifier:string;
/** We may get a reference to the underlying http error */
public httpError?:HttpErrorResponse;
public isValidationError:boolean = false;
/**
* Override toString to ensure the resource can
* be printed nicely on console and in errors
*/
public toString() {
return `[ErrorResource ${this.message}]`;
}
public get errorMessages():string[] {
if (this.isMultiErrorMessage()) {
return this.errors.map(error => error.message);

@ -115,6 +115,18 @@ export class HalResource {
this.halInitializer(this);
}
/**
* Override toString to ensure the resource can
* be printed nicely on console and in errors
*/
public toString() {
if (this.$href) {
return `[HalResource href=${this.$href}]`;
} else {
return `[HalResource id=${this.id}]`;
}
}
/**
* Returns the ID and ensures it's a string, null.
* Returns a string when:

@ -6,7 +6,7 @@ import {HalResource} from "core-app/modules/hal/resources/hal-resource";
@Injectable()
export class HalAwareErrorHandler extends ErrorHandler {
private text = {
internal_error: this.I18n.t('js.errors.internal')
internal_error: this.I18n.t('js.error.internal')
};
constructor(private readonly I18n:I18nService) {

@ -36,6 +36,8 @@ import {CollectionResource} from 'core-app/modules/hal/resources/collection-reso
import {HalLink, HalLinkInterface} from 'core-app/modules/hal/hal-link/hal-link';
import {initializeHalProperties} from 'core-app/modules/hal/helpers/hal-resource-builder';
import {URLParamsEncoder} from 'core-app/modules/hal/services/url-params-encoder';
import {ErrorReporter} from "core-app/sentry/sentry-reporter";
import {ErrorResource} from "core-app/modules/hal/resources/error-resource";
export interface HalResourceFactoryConfigInterface {
cls?:any;
@ -97,7 +99,9 @@ export class HalResourceService {
map((response:any) => this.createHalResource(response)),
catchError((error:HttpErrorResponse) => {
console.error(`Failed to ${method} ${href}: ${error.name}`);
return throwError(this.createHalResource(error.error));
const resource = this.createHalResource<ErrorResource>(error.error);
resource.httpError = error;
return throwError(resource);
})
) as any;
}

@ -76,6 +76,10 @@ export class SentryReporter implements ErrorReporter {
Sentry.init({
dsn: sentryElement.dataset.dsn!,
debug: !environment.production,
ignoreErrors: [
// Transition movements,
'The transition has been superseded by a different transition'
],
});
this.sentryLoaded(Sentry);
@ -107,11 +111,15 @@ export class SentryReporter implements ErrorReporter {
});
}
public captureException(err:Error) {
if (!this.client) {
public captureException(err:Error|string) {
if (!this.client || !err) {
return this.handleOfflineMessage('captureException', Array.from(arguments));
}
if (typeof err === 'string') {
return this.captureMessage(err, 'error');
}
this.client.withScope((scope:Scope) => {
this.setupContext(scope);
this.client.captureException(err);
@ -148,7 +156,7 @@ export class SentryReporter implements ErrorReporter {
scope.setTag('locale', I18n.locale);
scope.setTag('domain', window.location.hostname);
scope.setTag('url_path', window.location.pathname);
scope.setTag('url_query', window.location.search);
scope.setExtra('url_query', window.location.search);
/** Execute callbacks */
this.contextCallbacks.forEach(cb => cb(scope));

@ -34,7 +34,7 @@ module OpenProject
module VERSION #:nodoc:
MAJOR = 10
MINOR = 2
PATCH = 0
PATCH = 1
TINY = PATCH # Redmine compat
class << self

@ -42,7 +42,9 @@ class MeetingContentsController < ApplicationController
tab: @content_type.sub(/^meeting_/, '')
return
end
# go to an old version if a version id is given
@journaled_version = true
@content = @content.at_version params[:id] unless params[:id].blank?
render 'meeting_contents/show'
end

@ -54,7 +54,10 @@ See doc/COPYRIGHT.md for more details.
<% end -%>
</div>
<% resource = ::API::V3::MeetingContents::MeetingContentRepresenter.new(content, current_user: current_user, embed_links: true) %>
<%= list_attachments(resource) %>
<%# We cannot render attachments for journaled content %>
<% unless local_assigns[:journaled_version] %>
<% resource = ::API::V3::MeetingContents::MeetingContentRepresenter.new(content, current_user: current_user, embed_links: true) %>
<%= list_attachments(resource) %>
<% end %>
<%= render :partial => 'shared/meeting_header' %>

@ -19,4 +19,10 @@ See doc/COPYRIGHT.md for more details.
++#%>
<%= render(:partial => "meeting_contents/show", :locals => {:content => @content, :content_type => @content_type, :title => "#{l(:"label_#{@content_type}")}: #{link_to @meeting, @meeting}"}) %>
<%= render partial: "meeting_contents/show",
locals: {
content: @content,
journaled_version: @journaled_version,
content_type: @content_type,
title: "#{l(:"label_#{@content_type}")}: #{link_to @meeting, @meeting}"
} %>

Loading…
Cancel
Save